public bool IsSubscribed(string groupName, string serviceName, string clusters)
        {
            string key = ServiceInfo.GetKey(NamingUtils.GetGroupedName(serviceName, groupName), clusters);

            return(listenerMap.TryGetValue(key, out var eventListeners) &&
                   eventListeners != null && eventListeners.Any());
        }
Beispiel #2
0
        public async Task <ServiceInfo> GetServiceInfo(string serviceName, string clusters)
        {
            _logger.Debug($"failover-mode: {_failoverReactor.IsFailoverSwitch()}");

            string key = ServiceInfo.GetKey(serviceName, clusters);

            if (_failoverReactor.IsFailoverSwitch())
            {
                return(_failoverReactor.GetService(key));
            }

            ServiceInfo serviceObj = GetServiceInfoInner(serviceName, clusters);

            if (serviceObj == null)
            {
                TaskCompletionSource <bool> task = new TaskCompletionSource <bool>();
                if (_updating.TryAdd(key, task.Task))
                {
                    await UpdateServiceNow(serviceName, clusters);

                    task.SetResult(true);
                }
                else
                {
                    Task wait;
                    _updating.TryGetValue(key, out wait);
                    wait.Wait(DEFAULT_GET_DELAY);
                }
            }

            ScheduleUpdateIfAbsent(serviceName, clusters);

            return(_serviceInfoMap[key]);
        }
Beispiel #3
0
        /// <summary>
        /// Cache subscriber for redo.
        /// </summary>
        /// <param name="serviceName">service name</param>
        /// <param name="groupName">group name</param>
        /// <param name="cluster">cluster</param>
        public void CacheSubscriberForRedo(string serviceName, string groupName, string cluster)
        {
            string key      = ServiceInfo.GetKey(NamingUtils.GetGroupedName(serviceName, groupName), cluster);
            var    redoData = SubscriberRedoData.Build(serviceName, groupName, cluster);

            _subscribes.AddOrUpdate(key, redoData, (x, y) => redoData);
        }
 public UpdateModel(string serviceName, string groupName, string clusters)
 {
     this.ServiceName        = serviceName;
     this.GroupName          = groupName;
     this.Clusters           = clusters;
     this.GroupedServiceName = NamingUtils.GetGroupedName(serviceName, groupName);
     this.ServiceKey         = ServiceInfo.GetKey(GroupedServiceName, clusters);
 }
Beispiel #5
0
        /// <summary>
        /// Subscriber deregister, mark unregistering status as true.
        /// </summary>
        /// <param name="serviceName">service name</param>
        /// <param name="groupName">group name</param>
        /// <param name="cluster">cluster</param>
        public void SubscriberDeregister(string serviceName, string groupName, string cluster)
        {
            string key = ServiceInfo.GetKey(NamingUtils.GetGroupedName(serviceName, groupName), cluster);

            if (_subscribes.TryGetValue(key, out var data))
            {
                data.Unregistering = true;
            }
        }
Beispiel #6
0
        /// <summary>
        /// 直接获取内部服务
        /// </summary>
        private ServiceInfo GetServiceInfoInner(string serviceName, string clusters)
        {
            string key = ServiceInfo.GetKey(serviceName, clusters);

            ServiceInfo serviceInfo = null;

            _serviceInfoMap.TryGetValue(key, out serviceInfo);

            return(serviceInfo);
        }
        public void StopUpdateIfContain(string serviceName, string groupName, string clusters)
        {
            string serviceKey = ServiceInfo.GetKey(NamingUtils.GetGroupedName(serviceName, groupName), clusters);

            if (_timerMap.TryRemove(serviceKey, out var t))
            {
                t?.Change(Timeout.Infinite, Timeout.Infinite);
                t?.Dispose();

                _logger?.LogInformation("stop update task, servicekey:{0}", serviceKey);
            }
        }
        internal Dtos.ServiceInfo GetServiceInfo(string serviceName, string groupName, string clusters)
        {
            string groupedServiceName = NamingUtils.GetGroupedName(serviceName, groupName);
            string key = ServiceInfo.GetKey(groupedServiceName, clusters);

            /*if (failoverReactor.isFailoverSwitch())
             * {
             *  return failoverReactor.getService(key);
             * }*/

            return(serviceInfoMap.TryGetValue(key, out var serviceInfo) ? serviceInfo : null);
        }
        internal Dtos.ServiceInfo GetServiceInfo(string serviceName, string groupName, string clusters)
        {
            _logger?.LogDebug("failover-mode:{0}", _failoverReactor.IsFailoverSwitch());
            string groupedServiceName = NamingUtils.GetGroupedName(serviceName, groupName);
            string key = ServiceInfo.GetKey(groupedServiceName, clusters);

            if (_failoverReactor.IsFailoverSwitch())
            {
                return(_failoverReactor.GetService(key));
            }

            return(_serviceInfoMap.TryGetValue(key, out var serviceInfo) ? serviceInfo : null);
        }
        public void ScheduleUpdateIfAbsent(string serviceName, string groupName, string clusters)
        {
            string serviceKey = ServiceInfo.GetKey(NamingUtils.GetGroupedName(serviceName, groupName), clusters);

            if (_timerMap.TryGetValue(serviceKey, out _))
            {
                return;
            }

            var task = UpdateTask(serviceName, groupName, clusters);

            _timerMap.TryAdd(serviceKey, task);
        }
        private async Task RunUpdateTask(string serviceName, string groupName, string clusters)
        {
            int delayTime  = -1;
            var serviceKey = ServiceInfo.GetKey(NamingUtils.GetGroupedName(serviceName, groupName), clusters);

            try
            {
                if (!changeNotifier.IsSubscribed(groupName, serviceName, clusters) && !_updatingMap.ContainsKey(serviceKey))
                {
                    // TODO logger
                    return;
                }

                if (!serviceInfoHolder.GetServiceInfoMap().TryGetValue(serviceKey, out var serviceObj))
                {
                    serviceObj = await namingClientProxy.QueryInstancesOfService(serviceName, groupName, clusters, 0, false);

                    serviceInfoHolder.ProcessServiceInfo(serviceObj);
                    delayTime = DEFAULT_DELAY;

                    // TODO lastRefTime serviceObj.LastRefTime
                    return;
                }

                if (serviceObj.LastRefTime <= 0)
                {
                    serviceObj = await namingClientProxy.QueryInstancesOfService(serviceName, groupName, clusters, 0, false);

                    serviceInfoHolder.ProcessServiceInfo(serviceObj);
                }

                // TODO lastRefTime serviceObj.LastRefTime
                if (serviceObj.Hosts == null || serviceObj.Hosts.Any())
                {
                    // incFailCount
                    return;
                }

                delayTime = (int)serviceObj.CacheMillis * DEFAULT_UPDATE_CACHE_TIME_MULTIPLE;

                // resetFailCount
            }
            catch (System.Exception)
            {
                // logger
            }
            finally
            {
                // next
            }
        }
Beispiel #12
0
        public FailoverReactorTest()
        {
            _serviceMap = new ConcurrentDictionary <string, ServiceInfo>();
            var orderServiceInfo = new ServiceInfo();

            orderServiceInfo.Name      = "tms_order_v1";
            orderServiceInfo.GroupName = "tms";
            orderServiceInfo.Clusters  = "test";
            var orderInstance = new Instance()
            {
                InstanceId  = "1",
                Ip          = "192.168.1.50",
                Port        = 5000,
                Weight      = 1,
                ClusterName = "test",
                ServiceName = "tms_order_v1"
            };

            orderInstance.Metadata.Add("k1", "v1");
            orderServiceInfo.Hosts.Add(orderInstance);
            orderServiceInfo.LastRefTime = DateTime.Now.GetTimeStamp();

            var inquiryServiceInfo = new ServiceInfo();

            inquiryServiceInfo.Name      = "tms_inquiry_v1";
            inquiryServiceInfo.GroupName = "tms";
            inquiryServiceInfo.Clusters  = "test";
            var inquiryInstance = new Instance()
            {
                InstanceId  = "2",
                Ip          = "192.168.1.51",
                Port        = 5000,
                Weight      = 1,
                ClusterName = "test",
                ServiceName = "tms_order_v1"
            };

            inquiryInstance.Metadata.Add("k2", "v2");
            inquiryServiceInfo.Hosts.Add(inquiryInstance);
            inquiryServiceInfo.LastRefTime = DateTime.Now.GetTimeStamp();

            _serviceMap.TryAdd(orderServiceInfo.GetKey(), orderServiceInfo);
            _serviceMap.TryAdd(inquiryServiceInfo.GetKey(), inquiryServiceInfo);

            var mockHostReactor = new Mock <IHostReactor>();

            mockHostReactor.Setup(x => x.GetServiceInfoMap()).Returns(_serviceMap);

            _hostReactor = mockHostReactor.Object;
        }
Beispiel #13
0
        /// <summary>
        /// 添加订阅
        /// </summary>
        public void AddListener(ServiceInfo serviceInfo, string clusters, Action <IEvent> listener)
        {
            _logger.Info($"[LISTENER] adding {serviceInfo.Name} with {clusters} to listener map");

            var observers = new ConcurrentList <Action <IEvent> >();

            observers.Add(listener);

            observers = observerMap.GetOrAdd(ServiceInfo.GetKey(serviceInfo.Name, clusters), s => observers);
            if (observers != null)
            {
                observers.Add(listener);
            }
        }
        public void OnEvent(InstancesChangeEvent @event)
        {
            string key = ServiceInfo.GetKey(NamingUtils.GetGroupedName(@event.ServiceName, @event.GroupName), @event.Clusters);

            if (!listenerMap.TryGetValue(key, out var eventListeners))
            {
                return;
            }

            foreach (var listener in eventListeners)
            {
                listener.OnEvent(@event);
            }
        }
        public async Task <ServiceInfo> Subscribe(string serviceName, string groupName, string clusters)
        {
            string serviceNameWithGroup = NamingUtils.GetGroupedName(serviceName, groupName);
            string serviceKey           = ServiceInfo.GetKey(serviceNameWithGroup, clusters);

            if (!serviceInfoHolder.GetServiceInfoMap().TryGetValue(serviceKey, out var result))
            {
                result = await GetExecuteClientProxy().Subscribe(serviceName, groupName, clusters);
            }

            _serviceInfoUpdateService.ScheduleUpdateIfAbsent(serviceName, groupName, clusters);
            serviceInfoHolder.ProcessServiceInfo(result);
            return(result);
        }
Beispiel #16
0
        /// <summary>
        /// 添加订阅
        /// </summary>
        public void AddListener(ServiceInfo serviceInfo, string clusters, Action <IEvent> listener)
        {
            _logger.Info($"[LISTENER] adding {serviceInfo.Name} with {clusters} to listener map");

            var observers = new ConcurrentList <Action <IEvent> >();

            observers.Add(listener);

            observerMap.AddOrUpdate(ServiceInfo.GetKey(serviceInfo.Name, clusters), observers, (k, v) =>
            {
                v.Add(listener);
                return(v);
            });
        }
Beispiel #17
0
        /// <summary>
        /// 注销订阅
        /// </summary>
        public void RemoveListener(string serviceName, string clusters, Action <IEvent> listener)
        {
            _logger.Info($"[LISTENER] removing {serviceName} with {clusters} from listener key");

            ConcurrentList <Action <IEvent> > observers = null;

            if (observerMap.TryGetValue(ServiceInfo.GetKey(serviceName, clusters), out observers))
            {
                observers.Remove(listener);
                if (observers.Count <= 0)
                {
                    observerMap.TryRemove(ServiceInfo.GetKey(serviceName, clusters), out observers);
                }
            }
        }
        public void DeregisterListener(string groupName, string serviceName, string clusters, IEventListener listener)
        {
            string key = ServiceInfo.GetKey(NamingUtils.GetGroupedName(serviceName, groupName), clusters);

            if (!listenerMap.TryGetValue(key, out var eventListeners))
            {
                return;
            }

            eventListeners.Remove(listener);

            if (eventListeners == null || !eventListeners.Any())
            {
                listenerMap.TryRemove(key, out _);
            }
        }
Beispiel #19
0
        private Timer UpdateTask(string serviceName, string clusters)
        {
            return(new Timer(async x =>
            {
                var state = x as UpdateState;

                ServiceInfo serviceInfo = null;
                string key = ServiceInfo.GetKey(state.ServiceName, state.Clusters);
                Timer self = null;
                _timerMap.TryGetValue(key, out self);
                if (_serviceInfoMap.TryGetValue(key, out serviceInfo))
                {
                    if (serviceInfo.LastRefTime <= state.LastRefTime)
                    {
                        await UpdateServiceNow(state.ServiceName, state.Clusters);
                        _serviceInfoMap.TryGetValue(key, out serviceInfo);
                    }
                    else
                    {
                        try
                        {
                            await _namingProxy.QueryList(state.ServiceName, state.Clusters, 0, false);
                        }
                        catch (Exception ex)
                        {
                            _logger.Error(ex, $"[NA] failed to update serviceName: {state.ServiceName}");
                        }
                    }
                }
                else
                {
                    await UpdateServiceNow(state.ServiceName, state.Clusters);
                    Timer t = null;
                    if (_timerMap.TryGetValue(key, out t))
                    {
                        t.Change(DEFAULT_DELAY, Timeout.Infinite);
                    }
                    return;
                }

                state.LastRefTime = serviceInfo.LastRefTime;
                self?.Change(serviceInfo.CacheMillis, Timeout.Infinite);
            }, new UpdateState(serviceName, clusters), DEFAULT_DELAY, Timeout.Infinite));
        }
        public void RegisterListener(string groupName, string serviceName, string clusters, IEventListener listener)
        {
            string key = ServiceInfo.GetKey(NamingUtils.GetGroupedName(serviceName, groupName), clusters);

            if (!listenerMap.TryGetValue(key, out var eventListeners))
            {
                lock (obj)
                {
                    listenerMap.TryGetValue(key, out eventListeners);
                    if (eventListeners == null)
                    {
                        eventListeners   = new HashSet <IEventListener>();
                        listenerMap[key] = eventListeners;
                    }
                }
            }

            eventListeners.Add(listener);
        }
Beispiel #21
0
        public async Task <ServiceInfo> GetServiceInfo(string serviceName, string clusters)
        {
            _logger.Debug($"failover-mode: {_failoverReactor.IsFailoverSwitch()}");

            string key = ServiceInfo.GetKey(serviceName, clusters);

            if (_failoverReactor.IsFailoverSwitch())
            {
                return(_failoverReactor.GetService(key));
            }

            ServiceInfo serviceObj = GetServiceInfoInner(serviceName, clusters);

            if (serviceObj == null)
            {
                serviceObj = new ServiceInfo(serviceName, clusters);
                _serviceInfoMap.Add(key, serviceObj);

                _updatingMap.Add(serviceName, new object());
                await UpdateServiceNow(serviceName, clusters);

                _updatingMap.Remove(serviceName);
            }
            else if (_updatingMap.ContainsKey(serviceName))
            {
                if (UPDATE_HOLD_INTERVAL > 0)
                {
                    try
                    {
                        Monitor.Wait(serviceObj, UPDATE_HOLD_INTERVAL);
                    }
                    catch (Exception ex)
                    {
                        _logger.Error(ex, $"[getServiceInfo] serviceName: {serviceName}, clusters: {clusters}");
                    }
                }
            }

            ScheduleUpdateIfAbsent(serviceName, clusters);

            return(_serviceInfoMap[serviceObj.GetKey()]);
        }
        public void ScheduleUpdateIfAbsent(string serviceName, string groupName, string clusters)
        {
            string serviceKey = ServiceInfo.GetKey(NamingUtils.GetGroupedName(serviceName, groupName), clusters);

            var task = new TaskCompletionSource <bool>();

            if (_updatingMap.TryAdd(serviceKey, task.Task))
            {
                _ = RunUpdateTask(serviceName, groupName, clusters);
                task.SetResult(true);
            }
            else
            {
                // hold a moment waiting for update finish
                if (_updatingMap.TryGetValue(serviceKey, out var waitTask))
                {
                    waitTask.Wait(DEFAULT_DELAY);
                }
            }
        }
Beispiel #23
0
        /// <summary>
        /// 添加到主动更新清单中
        /// </summary>
        private void ScheduleUpdateIfAbsent(string serviceName, string clusters)
        {
            string key = ServiceInfo.GetKey(serviceName, clusters);

            if (_timerMap.ContainsKey(key))
            {
                return;
            }

            lock (_timerMap)
            {
                if (_timerMap.ContainsKey(key))
                {
                    return;
                }

                var t = UpdateTask(serviceName, clusters);
                _timerMap.Add(key, t);
            }
        }
Beispiel #24
0
        /// <summary>
        /// 创建服务信息刷新定时任务
        /// </summary>
        private void DiskFileWriter()
        {
            int duetime = DISK_FILE_WRITER_DUETIME;

            try
            {
                var files = DiskCache.MakeSureCacheDirExists(_failoverDir);
                if (files == null || files.Length <= 0)
                {
                    duetime = DIR_NOT_FOUND_DUETIME;
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "[NA] failed to backup file on startup.");
            }

            // 定时将新的服务信息保存至灾备目录文件中
            _diskFileWriter = new Timer(x =>
            {
                var map = _hostReactor.GetServiceInfoMap();
                foreach (var entry in map)
                {
                    ServiceInfo serviceInfo = entry.Value;

                    // 跳过系统配置
                    if (serviceInfo.GetKey().Equals(UtilAndComs.ALL_IPS) || serviceInfo.Name.Equals(UtilAndComs.ENV_LIST_KEY) ||
                        serviceInfo.Name.Equals(UtilAndComs.ENV_CONFIGS) ||
                        serviceInfo.Name.Equals(UtilAndComs.VIPCLIENT_CONFIG) ||
                        serviceInfo.Name.Equals(UtilAndComs.ALL_HOSTS))
                    {
                        continue;
                    }

                    DiskCache.WriteServiceInfo(_failoverDir, serviceInfo);
                }
                _diskFileWriter.Change(DISK_FILE_WRITER_PERIOD, Timeout.Infinite);
            }, null, duetime, Timeout.Infinite);
        }
Beispiel #25
0
        public void FailoverServiceInfoUpdateTest()
        {
            FailoverReactor.DISK_FILE_WRITER_DUETIME = 0;
            FailoverReactor.DISK_FILE_WRITER_PERIOD  = 500;
            FailoverReactor.DIR_NOT_FOUND_DUETIME    = 0;
            string path     = AppDomain.CurrentDomain.BaseDirectory;
            var    failover = new FailoverReactor(_hostReactor, path);

            var feeServiceInfo = new ServiceInfo();

            feeServiceInfo.Name      = "tms_fee_v1";
            feeServiceInfo.GroupName = "tms";
            feeServiceInfo.Clusters  = "test";
            var feeInstance = new Instance()
            {
                InstanceId  = "1",
                Ip          = "192.168.1.55",
                Port        = 5000,
                Weight      = 1,
                ClusterName = "test",
                ServiceName = "tms_fee_v1"
            };

            feeInstance.Metadata.Add("k1", "v1");
            feeServiceInfo.Hosts.Add(feeInstance);
            feeServiceInfo.LastRefTime = DateTime.Now.GetTimeStamp();

            _serviceMap.TryAdd(feeServiceInfo.GetKey(), feeServiceInfo);

            Thread.Sleep(500);

            var infos = DiskCache.GetServiceInfos(Path.Combine(path, FailoverReactor.FAILOVER_PATH));

            Assert.NotNull(infos);
            Assert.False(failover.IsFailoverSwitch());
            Assert.Equal(3, infos.Count);

            Directory.Delete(Path.Combine(path, FailoverReactor.FAILOVER_PATH), true);
        }
Beispiel #26
0
        public EventDispatcher()
        {
            Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    ServiceInfo info = null;
                    info             = changedServices.Take();

                    if (changedServices.TryTake(out info, TAKE_WAIT_MILLISECONDS_TIMEOUT))
                    {
                        try
                        {
                            ConcurrentList <Action <IEvent> > listeners = null;
                            if (observerMap.TryGetValue(info.GetKey(), out listeners))
                            {
                                if (listeners != null || listeners.Count > 0)
                                {
                                    var hosts = new ReadOnlyCollection <Instance>(info.Hosts);
                                    listeners.ForEach(x =>
                                    {
                                        x.Invoke(new NamingEvent(info.Name, info.GroupName, info.Clusters, hosts));
                                    });
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger.Error(ex, $"[NA] notify error for service: {info.Name}, clusters: {info.Clusters}");
                        }
                    }
                    else
                    {
                        continue;
                    }
                }
            });
        }
Beispiel #27
0
        /// <summary>
        /// 通过灾备目录中的服务信息恢复
        /// </summary>
        private void FailoverFileReader()
        {
            var domMap = new ConcurrentDictionary <string, ServiceInfo>();

            try
            {
                var files = DiskCache.MakeSureCacheDirExists(_failoverDir);

                foreach (var filePath in files)
                {
                    var fi = new FileInfo(filePath);

                    // 跳过灾备状态文件
                    if (fi.Name.Equals(UtilAndComs.FAILOVER_SWITCH))
                    {
                        continue;
                    }

                    string      content     = DiskCache.ReadFile(filePath);
                    ServiceInfo serviceInfo = JsonConvert.DeserializeObject <ServiceInfo>(content);
                    if (serviceInfo.Hosts != null && serviceInfo.Hosts.Count > 0)
                    {
                        domMap.AddOrUpdate(serviceInfo.GetKey(), serviceInfo, (k, v) => serviceInfo);
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "[NA] failed to read cache files");
            }

            if (domMap.Count > 0)
            {
                _serviceMap = domMap;
            }
        }
Beispiel #28
0
        public static async Task <Dictionary <string, ServiceInfo> > ReadAsync(string cacheDir)
        {
            Dictionary <string, ServiceInfo> domMap = new Dictionary <string, ServiceInfo>(16);

            try
            {
                var files = MakeSureCacheDirExists(cacheDir);

                foreach (string filePath in files)
                {
                    var fileName = System.Net.WebUtility.UrlDecode(filePath);

                    if (!(fileName.EndsWith(Constants.SERVICE_INFO_SPLITER + "meta") || fileName.EndsWith(Constants.SERVICE_INFO_SPLITER + "special-url")))
                    {
                        ServiceInfo     dom = new ServiceInfo(fileName);
                        List <Instance> ips = new List <Instance>();
                        dom.Hosts = ips;

                        ServiceInfo newFormat = null;

                        using FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                        byte[] readByte = new byte[fs.Length];
                        await fs.ReadAsync(readByte, 0, readByte.Length);

                        string readStr = Encoding.UTF8.GetString(readByte);
                        fs.Close();

                        using StringReader sr = new StringReader(readStr);
                        while (true)
                        {
                            var line = await sr.ReadLineAsync();

                            if (line == null || line.Length <= 0)
                            {
                                break;
                            }

                            try
                            {
                                if (!line.StartsWith("{"))
                                {
                                    continue;
                                }

                                newFormat = line.ToObj <ServiceInfo>();

                                if (string.IsNullOrWhiteSpace(newFormat.Name))
                                {
                                    ips.Add(line.ToObj <Instance>());
                                }
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(ex);
                            }
                        }

                        if (newFormat != null &&
                            !string.IsNullOrWhiteSpace(newFormat.Name) &&
                            newFormat.Hosts != null && newFormat.Hosts.Any())
                        {
                            domMap[dom.GetKey()] = newFormat;
                        }
                        else if (dom.Hosts != null && dom.Hosts.Any())
                        {
                            domMap[dom.GetKey()] = dom;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }

            return(domMap);
        }
Beispiel #29
0
        /// <summary>
        /// Remove subscriber for redo.
        /// </summary>
        /// <param name="serviceName">service name</param>
        /// <param name="groupName">group name</param>
        /// <param name="cluster">cluster</param>
        public void RemoveSubscriberForRedo(string serviceName, string groupName, string cluster)
        {
            string key = ServiceInfo.GetKey(NamingUtils.GetGroupedName(serviceName, groupName), cluster);

            _subscribes.TryRemove(key, out _);
        }
Beispiel #30
0
        /// <summary>
        /// 获取新服务信息并与缓存对比后返回最新
        /// </summary>
        public ServiceInfo ProcessServiceJson(string json)
        {
            ServiceInfo serviceInfo = JsonConvert.DeserializeObject <ServiceInfo>(json);
            ServiceInfo oldService  = null;

            _serviceInfoMap.TryGetValue(serviceInfo.GetKey(), out oldService);

            if (serviceInfo.Hosts == null || !serviceInfo.Validate())
            {
                return(oldService);
            }

            bool changed = false;

            if (oldService != null)
            {
                if (oldService.LastRefTime > serviceInfo.LastRefTime)
                {
                    _logger.Warn($"out of date data received, old-t: {oldService.LastRefTime}, new-t: {serviceInfo.LastRefTime}");
                }

                _serviceInfoMap.Add(serviceInfo.GetKey(), serviceInfo);

                var oldHostMap = oldService.Hosts.ToDictionary(x => x.ToInetAddr());
                var newHostMap = serviceInfo.Hosts.ToDictionary(x => x.ToInetAddr());

                var modHosts  = newHostMap.Where(x => oldHostMap.ContainsKey(x.Key) && !x.Value.ToString().Equals(oldHostMap[x.Key].ToString())).Select(x => x.Value);
                var newHosts  = newHostMap.Where(x => !oldHostMap.ContainsKey(x.Key)).Select(x => x.Value);
                var remvHosts = oldHostMap.Where(x => !newHostMap.ContainsKey(x.Key)).Select(x => x.Value);

                if (newHosts.Count() > 0)
                {
                    changed = true;
                    _logger.Info($"new ips ({newHosts.Count()}) service: {serviceInfo.GetKey()} -> {JsonConvert.SerializeObject(newHosts)}");
                }

                if (remvHosts.Count() > 0)
                {
                    changed = true;
                    _logger.Info($"removed ips ({remvHosts.Count()}) service: {serviceInfo.GetKey()} -> {JsonConvert.SerializeObject(remvHosts)}");
                }

                if (modHosts.Count() > 0)
                {
                    changed = true;
                    _logger.Info($"modified ips ({modHosts.Count()}) service: {serviceInfo.GetKey()} -> {JsonConvert.SerializeObject(modHosts)}");
                }

                if (newHosts.Count() > 0 || remvHosts.Count() > 0 || modHosts.Count() > 0)
                {
                    _eventDispatcher.ServiceChanged(serviceInfo);
                    DiskCache.WriteServiceInfo(_cacheDir, serviceInfo);
                }
            }
            else
            {
                changed = true;
                _logger.Info($"init new ips({serviceInfo.IpCount()}) service: {serviceInfo.GetKey()} -> {JsonConvert.SerializeObject(serviceInfo.Hosts)}");
                _serviceInfoMap.Add(serviceInfo.GetKey(), serviceInfo);
                _eventDispatcher.ServiceChanged(serviceInfo);
                DiskCache.WriteServiceInfo(_cacheDir, serviceInfo);
            }

            if (changed)
            {
                _logger.Info($"current ips({serviceInfo.IpCount()}) service: {serviceInfo.GetKey()} -> {JsonConvert.SerializeObject(serviceInfo.Hosts)}");
            }

            return(serviceInfo);
        }