节点在线、应用在线、配置在线使用令牌查询
大石头 authored at 2021-12-16 19:49:30
2.94 KiB
Stardust
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using NewLife;
using NewLife.Log;
using NewLife.Threading;
using Stardust.Data;
using Stardust.Data.Configs;

namespace Stardust.Server.Services
{
    /// <summary>在线服务</summary>
    public class OnlineService : IHostedService
    {
        #region 属性
        private TimerX _timer;
        private readonly ITracer _tracer;
        #endregion

        #region 构造
        public OnlineService(ITracer tracer) => _tracer = tracer;
        #endregion

        #region 方法
        public Task StartAsync(CancellationToken cancellationToken)
        {
            _timer = new TimerX(CheckOnline, null, 5_000, 30_000) { Async = true };

            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            _timer.TryDispose();

            return Task.CompletedTask;
        }

        private void CheckOnline(Object state)
        {
            // 节点超时
            var set = Setting.Current;
            var sessionTimeout = set.SessionTimeout;
            if (sessionTimeout > 0)
            {
                using var span = _tracer?.NewSpan(nameof(CheckOnline));

                var rs2 = AppOnline.ClearExpire(TimeSpan.FromSeconds(sessionTimeout));
                if (rs2 != null)
                {
                    foreach (var olt in rs2)
                    {
                        var app = olt?.App;
                        var msg = $"[{app}]登录于{olt.CreateTime},最后活跃于{olt.UpdateTime}";
                        var history = AppHistory.Create(app, "超时下线", true, msg, Environment.MachineName, olt.CreateIP);
                        history.Client = olt.Client;
                        history.Version = olt.Version;
                        history.SaveAsync();

                        if (app != null) CheckOffline(app, "超时下线");
                    }
                }

                var rs3 = ConfigOnline.ClearExpire(TimeSpan.FromSeconds(sessionTimeout));
            }

            // 注册中心
            {
                var rs = AppService.ClearExpire(TimeSpan.FromDays(7));
                var rs2 = AppConsume.ClearExpire(TimeSpan.FromSeconds(sessionTimeout));
            }
        }

        public static void CheckOffline(App app, String reason)
        {
            // 下线告警
            if (app.AlarmOnOffline && RobotHelper.CanAlarm(app.Category, app.WebHook))
            {
                // 查找该节点还有没有其它实例在线
                var olts = AppOnline.FindAllByApp(app.Id);
                if (olts.Count == 0)
                {
                    var msg = $"应用[{app.Name}]({app.DisplayName})已下线!{reason} IP={app.LastIP}";
                    RobotHelper.SendAlarm(app.Category, app.WebHook, "应用下线告警", msg);
                }
            }
        }
        #endregion
    }
}