双网关冗余(未完成)

This commit is contained in:
Kimdiego2098
2024-02-26 19:49:19 +08:00
parent 2166de8331
commit d3b87179aa
15 changed files with 551 additions and 280 deletions

View File

@@ -308,5 +308,75 @@
</summary>
<param name="pluginName">插件名称一般建议使用nameof()解决。</param>
</member>
<member name="T:TouchSocket.Rpc.GeneratorRpcProxyAttribute">
<summary>
标识该接口将使用源生成自动生成调用的代理类
</summary>
</member>
<member name="P:TouchSocket.Rpc.GeneratorRpcProxyAttribute.Prefix">
<summary>
调用键的前缀,包括服务的命名空间,类名,不区分大小写。格式:命名空间.类名
</summary>
</member>
<member name="P:TouchSocket.Rpc.GeneratorRpcProxyAttribute.GenericConstraintTypes">
<summary>
生成泛型方法的约束
</summary>
</member>
<member name="P:TouchSocket.Rpc.GeneratorRpcProxyAttribute.MethodInvoke">
<summary>
是否仅以函数名调用当为True是调用时仅需要传入方法名即可。
</summary>
</member>
<member name="P:TouchSocket.Rpc.GeneratorRpcProxyAttribute.Namespace">
<summary>
生成代码的命名空间
</summary>
</member>
<member name="P:TouchSocket.Rpc.GeneratorRpcProxyAttribute.ClassName">
<summary>
生成的类名不要包含“I”生成接口时会自动添加。
</summary>
</member>
<member name="P:TouchSocket.Rpc.GeneratorRpcProxyAttribute.GeneratorFlag">
<summary>
生成代码
</summary>
</member>
<member name="P:TouchSocket.Rpc.GeneratorRpcProxyAttribute.InheritedInterface">
<summary>
继承接口
</summary>
</member>
<member name="T:TouchSocket.Rpc.GeneratorRpcServerAttribute">
<summary>
标识将通过源生成器生成Rpc服务的调用委托。
</summary>
</member>
<member name="T:TouchSocket.Rpc.GeneratorRpcServerRegisterAttribute">
<summary>
标识将通过源生成器生成Rpc服务的注册代码。
</summary>
</member>
<member name="P:TouchSocket.Rpc.GeneratorRpcServerRegisterAttribute.MethodName">
<summary>
方法名称。默认是“RegisterAllFrom+AssemblyName”
</summary>
</member>
<member name="P:TouchSocket.Rpc.GeneratorRpcServerRegisterAttribute.ClassName">
<summary>
扩展类类名默认是“RegisterRpcServerFrom+AssemblyName+Extension”
</summary>
</member>
<member name="P:TouchSocket.Rpc.GeneratorRpcServerRegisterAttribute.Accessibility">
<summary>
访问修饰。
<para>
如果为<see cref="F:TouchSocket.Rpc.Accessibility.Both"/>将生成注册公共Rpc服务与非公共服务两个方法。其中非公共方法会在<see cref="P:TouchSocket.Rpc.GeneratorRpcServerRegisterAttribute.MethodName"/>之前以Internal开头。
如果为<see cref="F:TouchSocket.Rpc.Accessibility.Internal"/>将只生成注册非公共Rpc服务。
如果为<see cref="F:TouchSocket.Rpc.Accessibility.Public"/>将只生成注册公共Rpc服务。
</para>
</summary>
</member>
</members>
</doc>

View File

@@ -0,0 +1,18 @@
{
"Management": {
"RemoteUri": "127.0.0.1:7778", //主(备)站IP
"Port": 7777, //监听端口
"VerifyToken": "ThingsGateway", //登录token双方一致
"HeartbeatInterval": 3000, //心跳间隔
"MaxErrorCount": 3, //最大错误次数
"Redundancy": {
"Enable": false, //启用冗余
"IsPrimary": true, //是否主站
"IsHot": true
//默认主站优先,当主站恢复后,从站切换回主站,并重新开始向从站数据同步。
//备用站对外提供的数据都来自主站的数据同步
//热切换:主备站都完成对采集的初始化,并且都采集数据
//冷切换:主站完成对采集的初始化,并采集数据,只有当主站故障后,备用站才开始初始化并采集。
}
}
}

View File

@@ -0,0 +1,15 @@
{
"Management": {
"ServerUri": "127.0.0.1:7777", //IP
"ServerStandbyUri": "127.0.0.1:7777", //备用IP
"Port": 7777, //监听端口
"VerifyToken": "ThingsGateway",
"HeartbeatInterval": 3000, //心跳间隔
"MaxErrorCount": 3, //最大错误次数
"Redundancy": {
"Enable": true, //启用冗余
"IsPrimary": true, //是否主站
"IsHot": true //是否热冗余
}
}
}

View File

@@ -46,6 +46,8 @@ public class Startup : AppStartup
services.AddHostedService<CollectDeviceWorker>();
services.AddHostedService<BusinessDeviceWorker>();
services.AddHostedService<AlarmWorker>();
services.AddConfigurableOptions<ManagementOptions>();
services.AddHostedService<ManagementWoker>();
TypeExtension.DefaultDisplayNameFuncs.Add(a => a.GetCustomAttribute<DynamicPropertyAttribute>()?.Description);
}

View File

@@ -25,11 +25,18 @@
<PackageReference Include="CS-Script" Version="4.8.14" />
<!--CS-Script与Furion冲突直接安装覆盖版本-->
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.8.0" />
<PackageReference Include="TouchSocket.Dmtp" Version="2.0.0-beta.278" />
</ItemGroup>
<ItemGroup>
<None Update="Config\Management.Production.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Config\Management.Development.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Config\Gateway.Development.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

View File

@@ -446,20 +446,9 @@ public class AlarmWorker : BackgroundService
private EasyLock _easyLock = new(false);
private async Task CollectDeviceWorker_Starting()
{
await StartAsync();
}
private async Task CollectDeviceWorker_Stoping()
{
await StopAsync();
}
/// <inheritdoc/>
public override async Task StartAsync(CancellationToken cancellationToken)
{
_logger?.LogInformation("报警服务启动");
_appLifetime.ApplicationStarted.Register(() => { _easyLock.Release(); _easyLock = null; });
await base.StartAsync(cancellationToken);
}
@@ -467,7 +456,6 @@ public class AlarmWorker : BackgroundService
/// <inheritdoc/>
public override Task StopAsync(CancellationToken cancellationToken)
{
_logger?.LogInformation("报警服务停止");
return base.StopAsync(cancellationToken);
}
@@ -475,8 +463,7 @@ public class AlarmWorker : BackgroundService
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await _easyLock?.WaitAsync();
WorkerUtil.GetWoker<CollectDeviceWorker>().Starting += CollectDeviceWorker_Starting;
WorkerUtil.GetWoker<CollectDeviceWorker>().Stoping += CollectDeviceWorker_Stoping;
GlobalData = _serviceScope.ServiceProvider.GetService<GlobalData>();
while (!stoppingToken.IsCancellationRequested)
{

View File

@@ -187,22 +187,6 @@ public class BusinessDeviceWorker : DeviceWorker
await base.StartAsync(cancellationToken);
}
private async Task CollectDeviceWorker_Starting()
{
await CreatThreadsAsync();
}
private async Task CollectDeviceWorker_Started()
{
await Task.Delay(1000);
await StartAsync();
}
private async Task CollectDeviceWorker_Stoping()
{
await StopAsync();
}
/// <inheritdoc/>
public override async Task StopAsync(CancellationToken cancellationToken)
{
@@ -215,9 +199,7 @@ public class BusinessDeviceWorker : DeviceWorker
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await _easyLock?.WaitAsync();
WorkerUtil.GetWoker<CollectDeviceWorker>().Starting += CollectDeviceWorker_Starting;
WorkerUtil.GetWoker<CollectDeviceWorker>().Started += CollectDeviceWorker_Started;
WorkerUtil.GetWoker<CollectDeviceWorker>().Stoping += CollectDeviceWorker_Stoping;
PluginService = _serviceScope.ServiceProvider.GetService<IPluginService>();
GlobalData = _serviceScope.ServiceProvider.GetService<GlobalData>();
await WhileExecuteAsync(stoppingToken);

View File

@@ -116,6 +116,12 @@ public class CollectDeviceWorker : DeviceWorker
using var stoppingToken = new CancellationTokenSource();
_stoppingToken = stoppingToken.Token;
stoppingToken.Cancel();
await StopAsync();
await base.StopAsync(cancellationToken);
}
internal async Task StopAsync()
{
await BeforeRemoveAllChannelThreadAsync();
//停止其他后台服务
await ProtectedStoping();
@@ -123,18 +129,6 @@ public class CollectDeviceWorker : DeviceWorker
await RemoveAllChannelThreadAsync();
//停止其他后台服务
await ProtectedStoped();
await base.StopAsync(cancellationToken);
}
/// <inheritdoc/>
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await _easyLock?.WaitAsync();
PluginService = _serviceScope.ServiceProvider.GetService<IPluginService>();
GlobalData = _serviceScope.ServiceProvider.GetService<GlobalData>();
//重启采集线程,会启动其他后台服务
await RestartAsync();
await WhileExecuteAsync(stoppingToken);
}
#endregion worker服务

View File

@@ -0,0 +1,368 @@
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
using Furion.ConfigurableOptions;
using Furion.Logging.Extensions;
using Mapster;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Runtime.InteropServices;
using TouchSocket.Core;
using TouchSocket.Dmtp;
using TouchSocket.Dmtp.FileTransfer;
using TouchSocket.Dmtp.Rpc;
using TouchSocket.Rpc;
using TouchSocket.Sockets;
namespace ThingsGateway.Gateway.Application;
public class ManagementOptions : IConfigurableOptions
{
public string ServerUri { get; set; }
public string ServerStandbyUri { get; set; }
public int Port { get; set; }
public string VerifyToken { get; set; }
public int HeartbeatInterval { get; set; }
public int MaxErrorCount { get; set; }
public Redundancy Redundancy { get; set; }
}
public class Redundancy
{
public bool Enable { get; set; }
public bool IsPrimary { get; set; }
public bool IsHot { get; set; }
}
/// <summary>
/// TODO:网关管理服务
/// </summary>
public class ManagementWoker : BackgroundService
{
protected IServiceScope _serviceScope;
private readonly IHostApplicationLifetime _appLifetime;
private readonly ILogger _logger;
/// <inheritdoc cref="ManagementWoker"/>
public ManagementWoker(IServiceScopeFactory serviceScopeFactory, IHostApplicationLifetime appLifetime)
{
_serviceScope = serviceScopeFactory.CreateScope();
_logger = _serviceScope.ServiceProvider.GetService<ILoggerFactory>().CreateLogger("网关管理服务");
_appLifetime = appLifetime;
}
internal readonly EasyLock workerLock = new();
private async Task CollectDeviceWorker_Starting()
{
if (isStart)
{
await WorkerUtil.GetWoker<AlarmWorker>().StartAsync();
await WorkerUtil.GetWoker<BusinessDeviceWorker>().CreatThreadsAsync();
}
}
private async Task CollectDeviceWorker_Stoping()
{
await WorkerUtil.GetWoker<AlarmWorker>().StopAsync();
await WorkerUtil.GetWoker<BusinessDeviceWorker>().StopAsync();
}
private async Task CollectDeviceWorker_Started()
{
if (isStart)
{
await Task.Delay(1000);
await WorkerUtil.GetWoker<BusinessDeviceWorker>().StartAsync();
}
}
#region worker服务
private EasyLock _easyLock = new();
internal volatile bool isStart = false;
/// <inheritdoc/>
public override async Task StartAsync(CancellationToken cancellationToken)
{
_logger?.LogInformation("网关管理服务启动");
await _easyLock.WaitAsync();
_appLifetime.ApplicationStarted.Register(() => { _easyLock.Release(); _easyLock = null; });
await base.StartAsync(cancellationToken);
}
/// <inheritdoc/>
public override Task StopAsync(CancellationToken cancellationToken)
{
_logger?.LogInformation("网关管理服务停止");
return base.StopAsync(cancellationToken);
}
internal ManagementOptions options;
/// <inheritdoc/>
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await _easyLock?.WaitAsync();
var globalData = _serviceScope.ServiceProvider.GetService<GlobalData>();
options = App.GetOptions<ManagementOptions>();
var collectDeviceWorker = WorkerUtil.GetWoker<CollectDeviceWorker>();
collectDeviceWorker.Starting += CollectDeviceWorker_Starting;
collectDeviceWorker.Started += CollectDeviceWorker_Started;
collectDeviceWorker.Stoping += CollectDeviceWorker_Stoping;
if (options.Redundancy.Enable)
{
if (options.Redundancy.IsHot)
{
//热备冗余,直接启动采集服务
await collectDeviceWorker.RestartAsync();
}
var udpDmtp = GetUdpDmtp(options);
await udpDmtp.StartAsync();//启动
var firstStart = true;
while (!stoppingToken.IsCancellationRequested)
{
try
{
GatewayState? gatewayState = null;
try
{
await workerLock.WaitAsync();
{
var readErrorCount = 0;
while (readErrorCount < options.MaxErrorCount)
{
try
{
gatewayState = await udpDmtp.GetDmtpRpcActor().InvokeTAsync<GatewayState>("GetGatewayStateAsync", InvokeOption.WaitInvoke, isStart);
break;
}
catch
{
readErrorCount++;
}
}
}
}
finally
{
workerLock.Release();
}
if (gatewayState != null)
{
if (gatewayState.IsPrimary == options.Redundancy.IsPrimary)
{
_logger.LogInformation("主备站设置重复,退出冗余服务!");
await StartAsync();
break;
}
}
if (gatewayState == null)
{
//无法获取状态,启动本机
if (!isStart)
{
_logger.LogInformation("无法连接冗余站点,本机将切换到正常状态");
await StartAsync();
}
}
else if (gatewayState.IsPrimary)
{
//主站已经启动
if (gatewayState.IsStart)
{
if (isStart || firstStart)
{
_logger.LogInformation("主站已恢复,本机将切换到备用状态");
await StopAsync();
}
}
else
{
//等待主站切换到正常后,再停止从站
}
}
else
{
//从站已经启动
if (gatewayState.IsStart)
{
//等待从站切换到备用后,再启动主站
}
else
{
if (!isStart)
{
_logger.LogInformation("本机(主站)将切换到正常状态");
await StartAsync();
}
}
}
//TODO:发布到从站数据
//if (options.Redundancy.IsPrimary)
//{
// await udpDmtp.GetDmtpRpcActor().InvokeTAsync<GatewayState>("UpdateGatewayDataAsync", InvokeOption.WaitInvoke, globalData.CollectDevices, globalData.BusinessDevices);
//}
await Task.Delay(1000, stoppingToken);
}
catch (TaskCanceledException)
{
}
catch (ObjectDisposedException)
{
}
catch (Exception ex)
{
_logger.LogWarning(ex, "循环线程出错");
}
finally
{
firstStart = false;
}
}
}
else
{
isStart = true;
//无冗余,直接启动采集服务
await collectDeviceWorker.RestartAsync();
}
while (!stoppingToken.IsCancellationRequested)
{
try
{
await Task.Delay(60000, stoppingToken);
}
catch (TaskCanceledException)
{
}
catch (ObjectDisposedException)
{
}
catch (Exception ex)
{
_logger.LogWarning(ex, "循环线程出错");
}
}
}
private async Task StartAsync()
{
try
{
await workerLock.WaitAsync();
isStart = true;
if (options.Redundancy.IsHot)
{
await CollectDeviceWorker_Starting();
await CollectDeviceWorker_Started();
}
else
{
var collectDeviceWorker = WorkerUtil.GetWoker<CollectDeviceWorker>();
await collectDeviceWorker.RestartAsync();
}
}
finally
{
workerLock.Release();
}
}
private async Task StopAsync()
{
try
{
await workerLock.WaitAsync();
isStart = false;
if (options.Redundancy.IsHot)
{
await CollectDeviceWorker_Stoping();
}
else
{
var collectDeviceWorker = WorkerUtil.GetWoker<CollectDeviceWorker>();
await collectDeviceWorker.StopAsync();
}
}
finally
{
workerLock.Release();
}
}
#endregion worker服务
#region
private void LogOut(TouchSocket.Core.LogLevel logLevel, object source, string message, Exception exception)
{
_logger?.Log_Out(logLevel, source, message, exception);
}
private UdpDmtp GetUdpDmtp(ManagementOptions options)
{
var udpDmtp = new UdpDmtp();
var config = new TouchSocketConfig()
.SetRemoteIPHost(options.ServerUri)
.SetBindIPHost(options.Port)
.SetDmtpOption(
new DmtpOption() { VerifyToken = options.VerifyToken })
.ConfigureContainer(a =>
{
a.AddEasyLogger(LogOut);
a.AddRpcStore(store =>
{
store.RegisterServer<ReverseCallbackServer>();
// store.Container.RegisterSingleton<IHostApplicationLifetime>(_appLifetime);
// store.Container.RegisterSingleton(client);
});
})
.ConfigurePlugins(a =>
{
a.UseDmtpFileTransfer();//必须添加文件传输插件
//a.Add<FilePlugin>();
a.UseDmtpHeartbeat()//使用Dmtp心跳
.SetTick(TimeSpan.FromMilliseconds(options.HeartbeatInterval))
.SetMaxFailCount(options.MaxErrorCount);
a.UseDmtpRpc();
});
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
config.UseUdpConnReset();
}
udpDmtp.Setup(config);
return udpDmtp;
}
#endregion
}
internal class GatewayState
{
/// <summary>
/// 是否启动
/// </summary>
public bool IsStart { get; set; }
/// <summary>
/// 是否主站
/// </summary>
public bool IsPrimary { get; set; }
}

View File

@@ -0,0 +1,62 @@
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
using TouchSocket.Core;
using TouchSocket.Dmtp.Rpc;
using TouchSocket.Rpc;
namespace ThingsGateway.Gateway.Application;
internal class ReverseCallbackServer : RpcServer
{
private ILog _logger;
private ManagementWoker managementWoker;
public ReverseCallbackServer(ILog log)
{
_logger = log;
managementWoker = WorkerUtil.GetWoker<ManagementWoker>();
}
private EasyLock easyLock = new();
[DmtpRpc(true)]//使用方法名作为调用键
public async Task<GatewayState> GetGatewayStateAsync(bool isStart)
{
try
{
await easyLock.WaitAsync();
//冗余双方站点可能存在同时执行冗余切换的情况
{
GatewayState result = new();
result.IsStart = managementWoker.isStart;
//避免出现偶发同时启动
if (isStart && result.IsStart)
{
//请求方停止
result.RequestStop = true;
}
if (!isStart && !result.IsStart)
{
//请求方启动
result.RequestStop = false;
}
return result;
}
}
finally
{
easyLock.Release();
}
}
}

View File

@@ -1,78 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
using Furion.Logging.Extensions;
using Mapster;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace ThingsGateway.Gateway.Application;
/// <summary>
/// TODO:网关远程管理服务使用client模式适用于端口要求严格的网络环境
/// </summary>
public class ManagementSlaveWoker : BackgroundService
{
protected IServiceScope _serviceScope;
private readonly IHostApplicationLifetime _appLifetime;
private readonly ILogger _logger;
/// <inheritdoc cref="AlarmWorker"/>
public ManagementSlaveWoker(IServiceScopeFactory serviceScopeFactory, IHostApplicationLifetime appLifetime)
{
_serviceScope = serviceScopeFactory.CreateScope();
_logger = _serviceScope.ServiceProvider.GetService<ILoggerFactory>().CreateLogger("网关远程管理Slave服务");
_appLifetime = appLifetime;
}
#region worker服务
private EasyLock _easyLock = new();
/// <inheritdoc/>
public override async Task StartAsync(CancellationToken cancellationToken)
{
_logger?.LogInformation("网关远程管理Slave服务启动");
await _easyLock.WaitAsync();
_appLifetime.ApplicationStarted.Register(() => { _easyLock.Release(); _easyLock = null; });
await base.StartAsync(cancellationToken);
}
/// <inheritdoc/>
public override Task StopAsync(CancellationToken cancellationToken)
{
_logger?.LogInformation("网关远程管理Slave服务停止");
return base.StopAsync(cancellationToken);
}
/// <inheritdoc/>
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await _easyLock?.WaitAsync();
while (!stoppingToken.IsCancellationRequested)
{
try
{
await Task.Delay(60000, stoppingToken);
}
catch (TaskCanceledException)
{
}
catch (ObjectDisposedException)
{
}
}
}
#endregion worker服务
}

View File

@@ -1,78 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
using Furion.Logging.Extensions;
using Mapster;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace ThingsGateway.Gateway.Application;
/// <summary>
/// TODO:网关远程管理服务使用client模式适用于端口要求严格的网络环境
/// </summary>
public class ManagementMasterWoker : BackgroundService
{
protected IServiceScope _serviceScope;
private readonly IHostApplicationLifetime _appLifetime;
private readonly ILogger _logger;
/// <inheritdoc cref="AlarmWorker"/>
public ManagementMasterWoker(IServiceScopeFactory serviceScopeFactory, IHostApplicationLifetime appLifetime)
{
_serviceScope = serviceScopeFactory.CreateScope();
_logger = _serviceScope.ServiceProvider.GetService<ILoggerFactory>().CreateLogger("网关远程管理Master服务");
_appLifetime = appLifetime;
}
#region worker服务
private EasyLock _easyLock = new();
/// <inheritdoc/>
public override async Task StartAsync(CancellationToken cancellationToken)
{
_logger?.LogInformation("网关远程管理Master服务启动");
await _easyLock.WaitAsync();
_appLifetime.ApplicationStarted.Register(() => { _easyLock.Release(); _easyLock = null; });
await base.StartAsync(cancellationToken);
}
/// <inheritdoc/>
public override Task StopAsync(CancellationToken cancellationToken)
{
_logger?.LogInformation("网关远程管理Master服务停止");
return base.StopAsync(cancellationToken);
}
/// <inheritdoc/>
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await _easyLock?.WaitAsync();
while (!stoppingToken.IsCancellationRequested)
{
try
{
await Task.Delay(60000, stoppingToken);
}
catch (TaskCanceledException)
{
}
catch (ObjectDisposedException)
{
}
}
}
#endregion worker服务
}

View File

@@ -1,78 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
using Furion.Logging.Extensions;
using Mapster;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace ThingsGateway.Gateway.Application;
/// <summary>
/// 网关更新服务
/// </summary>
public class UpdatesWorker : BackgroundService
{
protected IServiceScope _serviceScope;
private readonly IHostApplicationLifetime _appLifetime;
private readonly ILogger _logger;
/// <inheritdoc cref="AlarmWorker"/>
public UpdatesWorker(IServiceScopeFactory serviceScopeFactory, IHostApplicationLifetime appLifetime)
{
_serviceScope = serviceScopeFactory.CreateScope();
_logger = _serviceScope.ServiceProvider.GetService<ILoggerFactory>().CreateLogger("网关更新服务");
_appLifetime = appLifetime;
}
#region worker服务
private EasyLock _easyLock = new();
/// <inheritdoc/>
public override async Task StartAsync(CancellationToken cancellationToken)
{
_logger?.LogInformation("更新服务启动");
await _easyLock.WaitAsync();
_appLifetime.ApplicationStarted.Register(() => { _easyLock.Release(); _easyLock = null; });
await base.StartAsync(cancellationToken);
}
/// <inheritdoc/>
public override Task StopAsync(CancellationToken cancellationToken)
{
_logger?.LogInformation("更新服务停止");
return base.StopAsync(cancellationToken);
}
/// <inheritdoc/>
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await _easyLock?.WaitAsync();
while (!stoppingToken.IsCancellationRequested)
{
try
{
await Task.Delay(60000, stoppingToken);
}
catch (TaskCanceledException)
{
}
catch (ObjectDisposedException)
{
}
}
}
#endregion worker服务
}

View File

@@ -13,7 +13,7 @@
<ItemGroup>
<PackageReference Include="NewLife.Core" Version="10.7.2024.202" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="TouchSocket" Version="2.0.0-beta.277" />
<PackageReference Include="TouchSocket" Version="2.0.0-beta.278" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'!='net45'">