using Consul; using Grpc.Extension.Abstract; using Grpc.Extension.Abstract.Discovery; using Grpc.Extension.Abstract.Model; using System; using System.Threading; namespace Grpc.Extension.Discovery.Consul { /// /// Consul服务注册 /// public class ConsulServiceRegister : IServiceRegister { private Timer _timerTTL; private string _guid; private ConsulClient _client; private ServiceRegisterModel _model; /// /// Consul服务注册 /// public ConsulServiceRegister() { this._guid = Guid.NewGuid().ToString(); } /// /// 注册服务到consul /// /// /// public void RegisterService(ServiceRegisterModel model) { this._model = model; this._client = CreateConsulClient(); RegisterServiceCore(); //因为公司的consul不支持consul主动检查服务状态,所以启动定时器主动去检测 _timerTTL = new Timer(state => DoTTL(), null, Timeout.Infinite, Timeout.Infinite); DoTTL(); } private void RegisterServiceCore() { var registration = new AgentServiceRegistration() { ID = GetServiceId(), Name = _model.DiscoveryServiceName, Tags = _model.DiscoveryServiceTags?.Split(','), EnableTagOverride = true, Address = _model.ServiceIp, Port = _model.ServicePort, //因为公司的consul不支持consul主动检查服务状态,所以注释掉 //Check = new AgentServiceCheck //{ // TCP = $"{_model.ServiceIp}:{_model.ServicePort}", // Interval = TimeSpan.FromSeconds(15), // Status = HealthStatus.Passing, // DeregisterCriticalServiceAfter = TimeSpan.FromMinutes(1) //} //因为公司的consul不支持consul主动检查服务状态,所以主动去TTL consul Check = new AgentCheckRegistration { ID = GetTTLCheckId(), Name = "ttlcheck", TTL = TimeSpan.FromSeconds(15), Status = HealthStatus.Passing, DeregisterCriticalServiceAfter = TimeSpan.FromMinutes(1), } }; _client.Agent.ServiceRegister(registration).Wait(); } /// /// 从consul反注册 /// public void DeregisterService() { _client.Agent.ServiceDeregister(GetServiceId()).Wait(); } private string GetServiceId() { return $"{_model.DiscoveryServiceName}-{(_model.ServiceIp)}-{(_model.ServicePort)}-{_guid}"; } private string GetTTLCheckId() { return $"service:{GetServiceId()}"; } private void DoTTL() { _timerTTL.Change(Timeout.Infinite, Timeout.Infinite); try { _client.Agent.PassTTL(GetTTLCheckId(), "timer:" + DateTime.Now).Wait(); } catch (Exception ex) { LoggerAccessor.Instance.OnLoggerError(new InternalException(GrpcErrorCode.Internal, "DoTTL", ex)); /* * passTTL会出现如下几种情况: * 1. consul服务重启中,ex会显示 connection refused by ip:port * 这种情况下,不去处理,等consul服务重启之后就好了 * 2. consul服务重启之后,会丢失之前的service,check,会有如下的错误: * Unexpected response, status code InternalServerError: CheckID "followme.srv.sms-192.168.3.10-10086-07f21040-0be9-4a73-b0a1-71755c6d6d46:ttlcheck" does not have associated TTL * 在这种情况下,需要处理,重新注册服务,check; */ if (ex.ToString().Contains($"CheckID \"{GetTTLCheckId()}\" does not have associated TTL")) { RegisterServiceCore(); } } finally { _timerTTL.Change(TimeSpan.FromSeconds(_model.DiscoveryTTLInterval), TimeSpan.FromSeconds(_model.DiscoveryTTLInterval)); } } private ConsulClient CreateConsulClient() { return new ConsulClient(conf => conf.Address = new Uri(_model.DiscoveryUrl)); } } }