mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-30 23:24:00 +08:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aec91da28b | ||
|
|
013ff394be |
@@ -61,7 +61,7 @@ public class HardwareJob : IJob, IHardwareJob
|
|||||||
var historyHardwareInfos = MemoryCache.Get<List<HistoryHardwareInfo>>(CacheKey);
|
var historyHardwareInfos = MemoryCache.Get<List<HistoryHardwareInfo>>(CacheKey);
|
||||||
if (historyHardwareInfos == null)
|
if (historyHardwareInfos == null)
|
||||||
{
|
{
|
||||||
using var db = _db;
|
using var db = DbContext.GetDB<HistoryHardwareInfo>(); ;
|
||||||
historyHardwareInfos = await db.Queryable<HistoryHardwareInfo>().Where(a => a.Date > DateTime.Now.AddDays(-3)).ToListAsync().ConfigureAwait(false);
|
historyHardwareInfos = await db.Queryable<HistoryHardwareInfo>().Where(a => a.Date > DateTime.Now.AddDays(-3)).ToListAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
MemoryCache.Set(CacheKey, historyHardwareInfos);
|
MemoryCache.Set(CacheKey, historyHardwareInfos);
|
||||||
@@ -81,7 +81,7 @@ public class HardwareJob : IJob, IHardwareJob
|
|||||||
{
|
{
|
||||||
if (HardwareInfo.MachineInfo == null)
|
if (HardwareInfo.MachineInfo == null)
|
||||||
{
|
{
|
||||||
await MachineInfo.RegisterAsync().ConfigureAwait(false);
|
MachineInfo.Register();
|
||||||
HardwareInfo.MachineInfo = MachineInfo.Current;
|
HardwareInfo.MachineInfo = MachineInfo.Current;
|
||||||
|
|
||||||
string currentPath = Directory.GetCurrentDirectory();
|
string currentPath = Directory.GetCurrentDirectory();
|
||||||
|
|||||||
@@ -22,12 +22,11 @@ public partial class SessionPage
|
|||||||
|
|
||||||
#region 查询
|
#region 查询
|
||||||
|
|
||||||
private async Task<QueryData<SessionOutput>> OnQueryAsync(QueryPageOptions options)
|
private Task<QueryData<SessionOutput>> OnQueryAsync(QueryPageOptions options)
|
||||||
{
|
{
|
||||||
return await Task.Run(async () =>
|
return Task.Run(() =>
|
||||||
{
|
{
|
||||||
var data = await SessionService.PageAsync(options);
|
return SessionService.PageAsync(options);
|
||||||
return data;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,12 @@
|
|||||||
<None Remove="$(SolutionDir)..\README.md" Pack="false" PackagePath="\" />
|
<None Remove="$(SolutionDir)..\README.md" Pack="false" PackagePath="\" />
|
||||||
<None Remove="$(SolutionDir)..\README.zh-CN.md" Pack="false" PackagePath="\" />
|
<None Remove="$(SolutionDir)..\README.zh-CN.md" Pack="false" PackagePath="\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\BlazorSetParametersAsyncGenerator\BlazorSetParametersAsyncGenerator.csproj" PrivateAssets="all" OutputItemType="Analyzer" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ThingsGateway.Razor" Version="$(SourceGeneratorVersion)" />
|
<!--<PackageReference Include="ThingsGateway.Razor" Version="$(SourceGeneratorVersion)" />-->
|
||||||
<!--<ProjectReference Include="..\ThingsGateway.Razor\ThingsGateway.Razor.csproj" />-->
|
<ProjectReference Include="..\ThingsGateway.Razor\ThingsGateway.Razor.csproj" />
|
||||||
<ProjectReference Include="..\ThingsGateway.SqlSugar\ThingsGateway.SqlSugar.csproj" />
|
<ProjectReference Include="..\ThingsGateway.SqlSugar\ThingsGateway.SqlSugar.csproj" />
|
||||||
<!--<PackageReference Include="SqlSugarCore" Version="5.1.4.195" />-->
|
<!--<PackageReference Include="SqlSugarCore" Version="5.1.4.195" />-->
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -160,8 +160,8 @@ public sealed class DatabaseLoggerProvider : ILoggerProvider, ISupportExternalSc
|
|||||||
_databaseLoggingWriter = _serviceScope.ServiceProvider.GetRequiredService(databaseLoggingWriterType) as IDatabaseLoggingWriter;
|
_databaseLoggingWriter = _serviceScope.ServiceProvider.GetRequiredService(databaseLoggingWriterType) as IDatabaseLoggingWriter;
|
||||||
|
|
||||||
// 创建长时间运行的后台任务,并将日志消息队列中数据写入存储中
|
// 创建长时间运行的后台任务,并将日志消息队列中数据写入存储中
|
||||||
_processQueueTask = Task.Factory.StartNew(async state => await ((DatabaseLoggerProvider)state).ProcessQueueAsync().ConfigureAwait(false)
|
_processQueueTask = Task.Factory.StartNew(ProcessQueueAsync
|
||||||
, this, TaskCreationOptions.LongRunning);
|
, TaskCreationOptions.LongRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -90,8 +90,7 @@ public sealed class FileLoggerProvider : ILoggerProvider, ISupportExternalScope
|
|||||||
_fileLoggingWriter = new FileLoggingWriter(this);
|
_fileLoggingWriter = new FileLoggingWriter(this);
|
||||||
|
|
||||||
// 创建长时间运行的后台任务,并将日志消息队列中数据写入文件中
|
// 创建长时间运行的后台任务,并将日志消息队列中数据写入文件中
|
||||||
_processQueueTask = Task.Factory.StartNew(async state => await ((FileLoggerProvider)state).ProcessQueueAsync().ConfigureAwait(false)
|
_processQueueTask = Task.Factory.StartNew(ProcessQueueAsync, TaskCreationOptions.LongRunning);
|
||||||
, this, TaskCreationOptions.LongRunning);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -110,8 +110,7 @@ internal sealed partial class SchedulerFactory : ISchedulerFactory
|
|||||||
if (Persistence is not null)
|
if (Persistence is not null)
|
||||||
{
|
{
|
||||||
// 创建长时间运行的后台任务,并将作业运行消息写入持久化中
|
// 创建长时间运行的后台任务,并将作业运行消息写入持久化中
|
||||||
_processQueueTask = Task.Factory.StartNew(async state => await ((SchedulerFactory)state).ProcessQueueAsync().ConfigureAwait(false)
|
_processQueueTask = Task.Factory.StartNew(ProcessQueueAsync, TaskCreationOptions.LongRunning);
|
||||||
, this, TaskCreationOptions.LongRunning);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -127,63 +127,57 @@ public class MachineInfo
|
|||||||
|
|
||||||
//static MachineInfo() => RegisterAsync().Wait(100);
|
//static MachineInfo() => RegisterAsync().Wait(100);
|
||||||
|
|
||||||
private static Task<MachineInfo>? _task;
|
|
||||||
/// <summary>异步注册一个初始化后的机器信息实例</summary>
|
/// <summary>异步注册一个初始化后的机器信息实例</summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static Task<MachineInfo> RegisterAsync()
|
public static MachineInfo Register()
|
||||||
{
|
{
|
||||||
|
if (Current != null) return Current;
|
||||||
if (_task != null) return _task;
|
// 文件缓存,加快机器信息获取。在Linux下,可能StarAgent以root权限写入缓存文件,其它应用以普通用户访问
|
||||||
|
var file = Path.GetTempPath().CombinePath("machine_info.json");
|
||||||
return _task = Task.Factory.StartNew(() =>
|
var json = "";
|
||||||
|
if (Current == null)
|
||||||
{
|
{
|
||||||
// 文件缓存,加快机器信息获取。在Linux下,可能StarAgent以root权限写入缓存文件,其它应用以普通用户访问
|
var f = file;
|
||||||
var file = Path.GetTempPath().CombinePath("machine_info.json");
|
if (File.Exists(f))
|
||||||
var json = "";
|
|
||||||
if (Current == null)
|
|
||||||
{
|
{
|
||||||
var f = file;
|
try
|
||||||
if (File.Exists(f))
|
|
||||||
{
|
{
|
||||||
try
|
//XTrace.WriteLine("Load MachineInfo {0}", f);
|
||||||
{
|
json = File.ReadAllText(f);
|
||||||
//XTrace.WriteLine("Load MachineInfo {0}", f);
|
Current = json.FromJsonNetString<MachineInfo>();
|
||||||
json = File.ReadAllText(f);
|
}
|
||||||
Current = json.FromJsonNetString<MachineInfo>();
|
catch (Exception ex)
|
||||||
}
|
{
|
||||||
catch (Exception ex)
|
if (XTrace.Log.Level <= LogLevel.Debug) NewLife.Log.XTrace.WriteException(ex);
|
||||||
{
|
|
||||||
if (XTrace.Log.Level <= LogLevel.Debug) NewLife.Log.XTrace.WriteException(ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var mi = Current ?? new MachineInfo();
|
var mi = Current ?? new MachineInfo();
|
||||||
|
|
||||||
mi.Init();
|
mi.Init();
|
||||||
Current = mi;
|
Current = mi;
|
||||||
|
|
||||||
try
|
try
|
||||||
|
{
|
||||||
|
var json2 = mi.ToJsonNetString();
|
||||||
|
if (json != json2)
|
||||||
{
|
{
|
||||||
var json2 = mi.ToJsonNetString();
|
File.WriteAllText(file.EnsureDirectory(true), json2);
|
||||||
if (json != json2)
|
|
||||||
{
|
|
||||||
File.WriteAllText(file.EnsureDirectory(true), json2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (XTrace.Log.Level <= LogLevel.Debug) NewLife.Log.XTrace.WriteException(ex);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (XTrace.Log.Level <= LogLevel.Debug) NewLife.Log.XTrace.WriteException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
return mi;
|
return mi;
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>获取当前信息,如果未设置则等待异步注册结果</summary>
|
/// <summary>获取当前信息,如果未设置则等待异步注册结果</summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static MachineInfo GetCurrent() => Current ?? RegisterAsync().ConfigureAwait(false).GetAwaiter().GetResult();
|
public static MachineInfo GetCurrent() => Current ?? Register();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public class Startup : AppStartup
|
|||||||
// 缓存
|
// 缓存
|
||||||
services.AddSingleton<ICache, MemoryCache>();
|
services.AddSingleton<ICache, MemoryCache>();
|
||||||
|
|
||||||
MachineInfo.RegisterAsync();
|
MachineInfo.Register();
|
||||||
|
|
||||||
// 配置雪花Id算法机器码
|
// 配置雪花Id算法机器码
|
||||||
YitIdHelper.SetIdGenerator(new IdGeneratorOptions
|
YitIdHelper.SetIdGenerator(new IdGeneratorOptions
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||||
|
<Import Project="$(SolutionDir)Version.props" />
|
||||||
<Import Project="$(SolutionDir)PackNuget.props" />
|
<Import Project="$(SolutionDir)PackNuget.props" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net8.0</TargetFrameworks>
|
<TargetFrameworks>net8.0</TargetFrameworks>
|
||||||
<Version>$(SourceGeneratorVersion)</Version>
|
|
||||||
<!--<UseRazorSourceGenerator>false</UseRazorSourceGenerator>-->
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="9.0.2" />
|
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="9.0.2" />
|
||||||
@@ -31,10 +29,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup Condition="'$(Configuration)' != 'Debug' ">
|
<!--<ItemGroup Condition="'$(Configuration)' != 'Debug' ">
|
||||||
<None Include="..\BlazorSetParametersAsyncGenerator\tools\*.ps1" PackagePath="tools" Pack="true" Visible="false" />
|
<None Include="..\BlazorSetParametersAsyncGenerator\tools\*.ps1" PackagePath="tools" Pack="true" Visible="false" />
|
||||||
<None Include="..\BlazorSetParametersAsyncGenerator\bin\$(Configuration)\netstandard2.0\BlazorSetParametersAsyncGenerator.dll" PackagePath="analyzers\dotnet\cs" Pack="true" Visible="false" />
|
<None Include="..\BlazorSetParametersAsyncGenerator\bin\$(Configuration)\netstandard2.0\BlazorSetParametersAsyncGenerator.dll" PackagePath="analyzers\dotnet\cs" Pack="true" Visible="false" />
|
||||||
</ItemGroup>
|
</ItemGroup>-->
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\BlazorSetParametersAsyncGenerator\BlazorSetParametersAsyncGenerator.csproj" PrivateAssets="all" OutputItemType="Analyzer" />
|
<ProjectReference Include="..\BlazorSetParametersAsyncGenerator\BlazorSetParametersAsyncGenerator.csproj" PrivateAssets="all" OutputItemType="Analyzer" />
|
||||||
|
|||||||
@@ -685,17 +685,20 @@ namespace ThingsGateway.SqlSugar
|
|||||||
|
|
||||||
private static Type GetCustomDbType(string className, Type type)
|
private static Type GetCustomDbType(string className, Type type)
|
||||||
{
|
{
|
||||||
if (className.Replace(".", "").Length + 1 == className.Length)
|
//命名空间相关
|
||||||
|
if (className.Replace(".", "").Length + 2 == className.Length)
|
||||||
{
|
{
|
||||||
var array = className.Split('.');
|
var array = className.Split('.');
|
||||||
foreach (var item in UtilMethods.EnumToDictionary<DbType>())
|
if (array.Length >= 3)
|
||||||
{
|
{
|
||||||
if (array.Last().StartsWith(item.Value.ToString()))
|
foreach (var item in UtilMethods.EnumToDictionary<DbType>())
|
||||||
{
|
{
|
||||||
|
if (array.Last().StartsWith(item.Value.ToString()))
|
||||||
var newName = array.First() + "." + item.Value.ToString() + "." + array.Last();
|
{
|
||||||
type = GetCustomTypeByClass(newName);
|
var newName = $"{array[0]}.{array[1]}.{item.Value}.{array.Last()}";
|
||||||
break;
|
type = GetCustomTypeByClass(newName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="SqlSugarCore.Dm" Version="8.8.0" />
|
<PackageReference Include="SqlSugarCore.Dm" Version="8.8.0" />
|
||||||
<PackageReference Include="SqlSugarCore.Kdbndp" Version="9.3.7.605" />
|
<PackageReference Include="SqlSugarCore.Kdbndp" Version="9.3.7.613" />
|
||||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="$(NET9Version)" />
|
<PackageReference Include="Microsoft.Data.Sqlite" Version="$(NET9Version)" />
|
||||||
<PackageReference Include="MySqlConnector" Version="2.4.0" />
|
<PackageReference Include="MySqlConnector" Version="2.4.0" />
|
||||||
<PackageReference Include="Npgsql" Version="9.0.3" />
|
<PackageReference Include="Npgsql" Version="9.0.3" />
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PluginVersion>10.8.0</PluginVersion>
|
<PluginVersion>10.8.2</PluginVersion>
|
||||||
<ProPluginVersion>10.8.0</ProPluginVersion>
|
<ProPluginVersion>10.8.2</ProPluginVersion>
|
||||||
<AuthenticationVersion>2.8.0</AuthenticationVersion>
|
<AuthenticationVersion>2.8.0</AuthenticationVersion>
|
||||||
<SourceGeneratorVersion>10.8.0</SourceGeneratorVersion>
|
<SourceGeneratorVersion>10.8.2</SourceGeneratorVersion>
|
||||||
<NET8Version>8.0.17</NET8Version>
|
<NET8Version>8.0.17</NET8Version>
|
||||||
<NET9Version>9.0.6</NET9Version>
|
<NET9Version>9.0.6</NET9Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
<!--<UseRazorSourceGenerator>false</UseRazorSourceGenerator>-->
|
<!--<UseRazorSourceGenerator>false</UseRazorSourceGenerator>-->
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ThingsGateway.Razor" Version="$(SourceGeneratorVersion)" />
|
<!--<PackageReference Include="ThingsGateway.Razor" Version="$(SourceGeneratorVersion)" />-->
|
||||||
<!--<ProjectReference Include="..\..\Admin\ThingsGateway.Razor\ThingsGateway.Razor.csproj" />-->
|
<ProjectReference Include="..\..\Admin\ThingsGateway.Razor\ThingsGateway.Razor.csproj" />
|
||||||
<ProjectReference Include="..\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj" />
|
<ProjectReference Include="..\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
@@ -22,8 +22,10 @@
|
|||||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Admin\BlazorSetParametersAsyncGenerator\BlazorSetParametersAsyncGenerator.csproj" PrivateAssets="all" OutputItemType="Analyzer" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,16 +23,17 @@ public class DoTask
|
|||||||
/// 取消令牌
|
/// 取消令牌
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private CancellationTokenSource? _cancelTokenSource;
|
private CancellationTokenSource? _cancelTokenSource;
|
||||||
|
private object? _state;
|
||||||
|
|
||||||
public DoTask(Func<CancellationToken, ValueTask> doWork, ILog logger, string taskName = null)
|
public DoTask(Func<object?, CancellationToken, Task> doWork, ILog logger, object? state = null, string taskName = null)
|
||||||
{
|
{
|
||||||
DoWork = doWork; Logger = logger; TaskName = taskName;
|
DoWork = doWork; Logger = logger; TaskName = taskName; _state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 执行任务方法
|
/// 执行任务方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<CancellationToken, ValueTask> DoWork { get; }
|
public Func<object?, CancellationToken, Task> DoWork { get; }
|
||||||
private ILog Logger { get; }
|
private ILog Logger { get; }
|
||||||
private Task PrivateTask { get; set; }
|
private Task PrivateTask { get; set; }
|
||||||
private string TaskName { get; }
|
private string TaskName { get; }
|
||||||
@@ -74,7 +75,7 @@ public class DoTask
|
|||||||
{
|
{
|
||||||
if (_cancelTokenSource.IsCancellationRequested)
|
if (_cancelTokenSource.IsCancellationRequested)
|
||||||
return;
|
return;
|
||||||
await DoWork(_cancelTokenSource.Token).ConfigureAwait(false);
|
await DoWork(_state, _cancelTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
using TouchSocket.Core;
|
||||||
|
|
||||||
|
namespace ThingsGateway.Gateway.Application;
|
||||||
|
|
||||||
|
public class ScheduledTask
|
||||||
|
{
|
||||||
|
private TimeSpan _interval { get; }
|
||||||
|
private TimeSpan _interval10 = TimeSpan.FromMilliseconds(10);
|
||||||
|
private double _intervalMS { get; }
|
||||||
|
private readonly Func<object?, CancellationToken, Task> _taskFunc;
|
||||||
|
private readonly CancellationToken _token;
|
||||||
|
private Timer? _timer;
|
||||||
|
private object? _state;
|
||||||
|
private ILog LogMessage;
|
||||||
|
private volatile int _isRunning = 0;
|
||||||
|
private volatile int _pendingTriggers = 0;
|
||||||
|
|
||||||
|
public ScheduledTask(TimeSpan interval, Func<object?, CancellationToken, Task> taskFunc, object? state, ILog log, CancellationToken token)
|
||||||
|
{
|
||||||
|
LogMessage = log;
|
||||||
|
_state = state;
|
||||||
|
_interval = interval;
|
||||||
|
_intervalMS = interval.TotalMilliseconds;
|
||||||
|
_taskFunc = taskFunc;
|
||||||
|
_token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
_timer?.Dispose();
|
||||||
|
_timer = new Timer(TimerCallback, _state, TimeSpan.Zero, _interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TimerCallback(object? state)
|
||||||
|
{
|
||||||
|
_ = Do(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Do(object? state)
|
||||||
|
{
|
||||||
|
if (_token.IsCancellationRequested)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Interlocked.Exchange(ref _pendingTriggers, 1);
|
||||||
|
|
||||||
|
if (Interlocked.Exchange(ref _isRunning, 1) == 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _taskFunc(state, _token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogMessage.LogWarning(ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Interlocked.Exchange(ref _isRunning, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Interlocked.Exchange(ref _pendingTriggers, 0) == 1)
|
||||||
|
{
|
||||||
|
if (!_token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
DelayDo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DelayDo()
|
||||||
|
{
|
||||||
|
// 延迟触发下一次
|
||||||
|
_timer?.Change(_interval10, _interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Change(int dueTime, int period)
|
||||||
|
{
|
||||||
|
_timer?.Change(dueTime, period);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
_timer?.Dispose();
|
||||||
|
_timer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -41,7 +41,7 @@ public class SmartTriggerScheduler
|
|||||||
|
|
||||||
// 否则启动执行任务
|
// 否则启动执行任务
|
||||||
_isRunning = true;
|
_isRunning = true;
|
||||||
_ = Task.Run(ExecuteLoop); // 开启异步执行循环(非阻塞)
|
_ = Task.Run(ExecuteLoop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
namespace ThingsGateway.Gateway.Application;
|
||||||
|
|
||||||
|
public class TaskSchedulerLoop
|
||||||
|
{
|
||||||
|
public readonly List<ScheduledTask> Tasks;
|
||||||
|
|
||||||
|
public TaskSchedulerLoop(List<ScheduledTask> tasks)
|
||||||
|
{
|
||||||
|
Tasks = tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
foreach (var task in Tasks)
|
||||||
|
{
|
||||||
|
task.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
foreach (var task in Tasks)
|
||||||
|
{
|
||||||
|
task.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void Change(int dueTime, int period)
|
||||||
|
{
|
||||||
|
foreach (var task in Tasks)
|
||||||
|
{
|
||||||
|
task.Change(dueTime, period);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -171,7 +171,7 @@ public abstract class BusinessBase : DriverBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override ValueTask StartAsync(CancellationToken cancellationToken)
|
internal override Task StartAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
TimeTick = new TimeTick(CurrentDevice.IntervalTime);
|
TimeTick = new TimeTick(CurrentDevice.IntervalTime);
|
||||||
return base.StartAsync(cancellationToken);
|
return base.StartAsync(cancellationToken);
|
||||||
|
|||||||
@@ -49,8 +49,7 @@ public abstract class BusinessBaseWithCacheIntervalAlarmModel<VarModel, DevModel
|
|||||||
|
|
||||||
GlobalData.AlarmChangedEvent += AlarmValueChange;
|
GlobalData.AlarmChangedEvent += AlarmValueChange;
|
||||||
// 解绑全局数据的事件
|
// 解绑全局数据的事件
|
||||||
GlobalData.VariableValueChangeEvent -= VariableValueChange;
|
|
||||||
GlobalData.DeviceStatusChangeEvent -= DeviceStatusChange;
|
|
||||||
|
|
||||||
// 根据业务属性的缓存是否为间隔上传来决定事件绑定
|
// 根据业务属性的缓存是否为间隔上传来决定事件绑定
|
||||||
if (_businessPropertyWithCacheInterval.BusinessUpdateEnum != BusinessUpdateEnum.Interval)
|
if (_businessPropertyWithCacheInterval.BusinessUpdateEnum != BusinessUpdateEnum.Interval)
|
||||||
@@ -129,6 +128,7 @@ public abstract class BusinessBaseWithCacheIntervalAlarmModel<VarModel, DevModel
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
|
|
||||||
// 解绑事件
|
// 解绑事件
|
||||||
GlobalData.AlarmChangedEvent -= AlarmValueChange;
|
GlobalData.AlarmChangedEvent -= AlarmValueChange;
|
||||||
GlobalData.VariableValueChangeEvent -= VariableValueChange;
|
GlobalData.VariableValueChangeEvent -= VariableValueChange;
|
||||||
|
|||||||
@@ -50,10 +50,6 @@ public abstract class BusinessBaseWithCacheIntervalDeviceModel<VarModel, DevMode
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 注销全局变量值改变事件和设备状态改变事件的订阅,以防止重复订阅
|
|
||||||
GlobalData.VariableValueChangeEvent -= VariableValueChange;
|
|
||||||
GlobalData.DeviceStatusChangeEvent -= DeviceStatusChange;
|
|
||||||
|
|
||||||
// 如果不是间隔上传,则订阅全局变量值改变事件和设备状态改变事件,并触发一次事件处理
|
// 如果不是间隔上传,则订阅全局变量值改变事件和设备状态改变事件,并触发一次事件处理
|
||||||
if (_businessPropertyWithCacheInterval.BusinessUpdateEnum != BusinessUpdateEnum.Interval)
|
if (_businessPropertyWithCacheInterval.BusinessUpdateEnum != BusinessUpdateEnum.Interval)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ public abstract class BusinessBaseWithCacheIntervalVariableModel<VarModel> : Bus
|
|||||||
_exTTimerTick = new TimeTick(_businessPropertyWithCacheInterval.BusinessInterval);
|
_exTTimerTick = new TimeTick(_businessPropertyWithCacheInterval.BusinessInterval);
|
||||||
|
|
||||||
// 注册变量值变化事件处理程序
|
// 注册变量值变化事件处理程序
|
||||||
GlobalData.VariableValueChangeEvent -= VariableValueChange;
|
|
||||||
if (_businessPropertyWithCacheInterval.BusinessUpdateEnum != BusinessUpdateEnum.Interval)
|
if (_businessPropertyWithCacheInterval.BusinessUpdateEnum != BusinessUpdateEnum.Interval)
|
||||||
{
|
{
|
||||||
GlobalData.VariableValueChangeEvent += VariableValueChange;
|
GlobalData.VariableValueChangeEvent += VariableValueChange;
|
||||||
@@ -164,7 +163,7 @@ public abstract class BusinessBaseWithCacheIntervalVariableModel<VarModel> : Bus
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="variableRuntime">变量运行时对象</param>
|
/// <param name="variableRuntime">变量运行时对象</param>
|
||||||
/// <param name="variable">变量数据</param>
|
/// <param name="variable">变量数据</param>
|
||||||
private void VariableValueChange(VariableRuntime variableRuntime, VariableBasicData variable)
|
protected void VariableValueChange(VariableRuntime variableRuntime, VariableBasicData variable)
|
||||||
{
|
{
|
||||||
if (CurrentDevice.Pause == true)
|
if (CurrentDevice.Pause == true)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -234,16 +234,17 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
|||||||
return ThreadRunReturnTypeEnum.None;
|
return ThreadRunReturnTypeEnum.None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ReadResultCount readResultCount = new();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 执行读取等方法,如果插件不支持读取,而是自更新值的话,需重写此方法
|
/// 执行读取等方法,如果插件不支持读取,而是自更新值的话,需重写此方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected override async ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ReadResultCount readResultCount = new();
|
readResultCount.Reset();
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -545,6 +546,13 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
|||||||
public int deviceMethodsVariableSuccessNum = 0;
|
public int deviceMethodsVariableSuccessNum = 0;
|
||||||
public int deviceSourceVariableFailedNum = 0;
|
public int deviceSourceVariableFailedNum = 0;
|
||||||
public int deviceSourceVariableSuccessNum = 0;
|
public int deviceSourceVariableSuccessNum = 0;
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
deviceMethodsVariableFailedNum = 0;
|
||||||
|
deviceMethodsVariableSuccessNum = 0;
|
||||||
|
deviceSourceVariableFailedNum = 0;
|
||||||
|
deviceSourceVariableSuccessNum = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 写入方法
|
#region 写入方法
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ public abstract class DriverBase : DisposableObject, IDriver
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cancellationToken">取消操作的令牌。</param>
|
/// <param name="cancellationToken">取消操作的令牌。</param>
|
||||||
/// <returns>表示异步操作的任务。</returns>
|
/// <returns>表示异步操作的任务。</returns>
|
||||||
internal virtual async ValueTask StartAsync(CancellationToken cancellationToken)
|
internal virtual async Task StartAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// 如果已经执行过初始化,则直接返回
|
// 如果已经执行过初始化,则直接返回
|
||||||
if (IsStarted)
|
if (IsStarted)
|
||||||
@@ -426,7 +426,7 @@ public abstract class DriverBase : DisposableObject, IDriver
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 间隔执行
|
/// 间隔执行
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected abstract ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken);
|
protected abstract Task ProtectedExecuteAsync(CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
|||||||
|
|
||||||
static DeviceThreadManage()
|
static DeviceThreadManage()
|
||||||
{
|
{
|
||||||
Task.Factory.StartNew(async () => await SetCycleInterval().ConfigureAwait(false), TaskCreationOptions.LongRunning);
|
Task.Factory.StartNew(SetCycleInterval, TaskCreationOptions.LongRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task SetCycleInterval()
|
private static async Task SetCycleInterval()
|
||||||
@@ -385,14 +385,20 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化业务线程
|
|
||||||
var driverTask = new DoTask(t => DoWork(driver, IsCollectChannel, t), driver.LogMessage, null);
|
|
||||||
DriverTasks.TryAdd(driver.DeviceId, driverTask);
|
|
||||||
|
|
||||||
token.Register(driver.Stop);
|
token.Register(driver.Stop);
|
||||||
|
|
||||||
driverTask.Start(token);
|
|
||||||
|
|
||||||
|
if (driver.IsInitSuccess)
|
||||||
|
{
|
||||||
|
|
||||||
|
// 初始化业务线程
|
||||||
|
var driverTask = new DoTask(DoWork, driver.LogMessage, driver);
|
||||||
|
DriverTasks.TryAdd(driver.DeviceId, driverTask);
|
||||||
|
|
||||||
|
|
||||||
|
driverTask.Start(token);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
@@ -463,12 +469,12 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
|||||||
await deviceIds.ParallelForEachAsync(async (deviceId, cancellationToken) =>
|
await deviceIds.ParallelForEachAsync(async (deviceId, cancellationToken) =>
|
||||||
{
|
{
|
||||||
// 查找具有指定设备ID的驱动程序对象
|
// 查找具有指定设备ID的驱动程序对象
|
||||||
if (!Drivers.TryRemove(deviceId, out var driver)) return;
|
if (Drivers.TryRemove(deviceId, out var driver))
|
||||||
if (!DriverTasks.TryRemove(deviceId, out var task)) return;
|
|
||||||
|
|
||||||
if (IsCollectChannel == true)
|
|
||||||
{
|
{
|
||||||
saveVariableRuntimes.AddRange(driver.IdVariableRuntimes.Where(a => a.Value.SaveValue && !a.Value.DynamicVariable).Select(a => a.Value));
|
if (IsCollectChannel == true)
|
||||||
|
{
|
||||||
|
saveVariableRuntimes.AddRange(driver.IdVariableRuntimes.Where(a => a.Value.SaveValue && !a.Value.DynamicVariable).Select(a => a.Value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 取消驱动程序的操作
|
// 取消驱动程序的操作
|
||||||
@@ -480,7 +486,12 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
|||||||
token.Dispose();
|
token.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await task.StopAsync().ConfigureAwait(false);
|
|
||||||
|
if (DriverTasks.TryRemove(deviceId, out var task))
|
||||||
|
{
|
||||||
|
await task.StopAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
|
|
||||||
@@ -532,16 +543,16 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
|||||||
return driver;
|
return driver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task DoWork(object? state, CancellationToken token)
|
||||||
private static async ValueTask DoWork(DriverBase driver, bool? isCollectChannel, CancellationToken token)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (state is not DriverBase driver) return;
|
||||||
// 只有当驱动成功初始化后才执行操作
|
// 只有当驱动成功初始化后才执行操作
|
||||||
if (driver.IsInitSuccess)
|
if (driver.IsInitSuccess)
|
||||||
{
|
{
|
||||||
if (!driver.IsStarted)
|
if (!driver.IsStarted)
|
||||||
await driver.StartAsync(token).ConfigureAwait(false); // 调用驱动的启动前异步方法,如果已经执行,会直接返回
|
await driver.StartAsync(token).ConfigureAwait(false);
|
||||||
|
|
||||||
var result = await driver.ExecuteAsync(token).ConfigureAwait(false); // 执行驱动的异步执行操作
|
var result = await driver.ExecuteAsync(token).ConfigureAwait(false); // 执行驱动的异步执行操作
|
||||||
|
|
||||||
@@ -549,7 +560,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
|||||||
if (result == ThreadRunReturnTypeEnum.None)
|
if (result == ThreadRunReturnTypeEnum.None)
|
||||||
{
|
{
|
||||||
// 如果驱动处于离线状态且为采集驱动,则根据配置的间隔时间进行延迟
|
// 如果驱动处于离线状态且为采集驱动,则根据配置的间隔时间进行延迟
|
||||||
if (driver.CurrentDevice.DeviceStatus == DeviceStatusEnum.OffLine && isCollectChannel == true)
|
if (driver.CurrentDevice.DeviceStatus == DeviceStatusEnum.OffLine && driver.IsCollectDevice == true)
|
||||||
{
|
{
|
||||||
var collectBase = (CollectBase)driver;
|
var collectBase = (CollectBase)driver;
|
||||||
if (collectBase.CollectProperties.ReIntervalTime > 0)
|
if (collectBase.CollectProperties.ReIntervalTime > 0)
|
||||||
|
|||||||
@@ -134,11 +134,7 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 主站
|
/// 主站
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="tcpDmtpService">服务</param>
|
private async Task DoMasterWork(object? state, CancellationToken stoppingToken)
|
||||||
/// <param name="syncInterval">同步间隔</param>
|
|
||||||
/// <param name="log">log</param>
|
|
||||||
/// <param name="stoppingToken">取消任务的 CancellationToken</param>
|
|
||||||
private static async ValueTask DoMasterWork(TcpDmtpService tcpDmtpService, int syncInterval, ILog log, CancellationToken stoppingToken)
|
|
||||||
{
|
{
|
||||||
// 延迟一段时间,避免过于频繁地执行任务
|
// 延迟一段时间,避免过于频繁地执行任务
|
||||||
await Task.Delay(500, stoppingToken).ConfigureAwait(false);
|
await Task.Delay(500, stoppingToken).ConfigureAwait(false);
|
||||||
@@ -155,7 +151,7 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (tcpDmtpService.Clients.Count != 0)
|
if (TcpDmtpService.Clients.Count != 0)
|
||||||
{
|
{
|
||||||
online = true;
|
online = true;
|
||||||
}
|
}
|
||||||
@@ -164,12 +160,12 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo
|
|||||||
{
|
{
|
||||||
var deviceRunTimes = GlobalData.ReadOnlyIdDevices.Where(a => a.Value.IsCollect == true).Select(a => a.Value).Adapt<List<DeviceDataWithValue>>();
|
var deviceRunTimes = GlobalData.ReadOnlyIdDevices.Where(a => a.Value.IsCollect == true).Select(a => a.Value).Adapt<List<DeviceDataWithValue>>();
|
||||||
|
|
||||||
foreach (var item in tcpDmtpService.Clients)
|
foreach (var item in TcpDmtpService.Clients)
|
||||||
{
|
{
|
||||||
// 将 GlobalData.CollectDevices 和 GlobalData.Variables 同步到从站
|
// 将 GlobalData.CollectDevices 和 GlobalData.Variables 同步到从站
|
||||||
await item.GetDmtpRpcActor().InvokeAsync(
|
await item.GetDmtpRpcActor().InvokeAsync(
|
||||||
nameof(ReverseCallbackServer.UpData), null, waitInvoke, deviceRunTimes).ConfigureAwait(false);
|
nameof(ReverseCallbackServer.UpData), null, waitInvoke, deviceRunTimes).ConfigureAwait(false);
|
||||||
log?.LogTrace($"{item.GetIPPort()} Update StandbyStation data success");
|
LogMessage?.LogTrace($"{item.GetIPPort()} Update StandbyStation data success");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -177,9 +173,9 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// 输出警告日志,指示同步数据到从站时发生错误
|
// 输出警告日志,指示同步数据到从站时发生错误
|
||||||
log?.LogWarning(ex, "Synchronize data to standby site error");
|
LogMessage?.LogWarning(ex, "Synchronize data to standby site error");
|
||||||
}
|
}
|
||||||
await Task.Delay(syncInterval, stoppingToken).ConfigureAwait(false);
|
await Task.Delay(RedundancyOptions.SyncInterval, stoppingToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
@@ -189,17 +185,14 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
log?.LogWarning(ex, "Execute");
|
LogMessage?.LogWarning(ex, "Execute");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 从站
|
/// 从站
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="tcpDmtpClient">服务</param>
|
private async Task DoSlaveWork(object? state, CancellationToken stoppingToken)
|
||||||
/// <param name="redundancy">冗余配置</param>
|
|
||||||
/// <param name="stoppingToken">取消任务的 CancellationToken</param>
|
|
||||||
private async ValueTask DoSlaveWork(TcpDmtpClient tcpDmtpClient, RedundancyOptions redundancy, CancellationToken stoppingToken)
|
|
||||||
{
|
{
|
||||||
// 延迟一段时间,避免过于频繁地执行任务
|
// 延迟一段时间,避免过于频繁地执行任务
|
||||||
await Task.Delay(5000, stoppingToken).ConfigureAwait(false);
|
await Task.Delay(5000, stoppingToken).ConfigureAwait(false);
|
||||||
@@ -216,31 +209,31 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await tcpDmtpClient.TryConnectAsync().ConfigureAwait(false);
|
await TcpDmtpClient.TryConnectAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
{
|
{
|
||||||
// 初始化读取错误计数器
|
// 初始化读取错误计数器
|
||||||
var readErrorCount = 0;
|
var readErrorCount = 0;
|
||||||
// 当读取错误次数小于最大错误计数时循环执行
|
// 当读取错误次数小于最大错误计数时循环执行
|
||||||
while (readErrorCount < redundancy.MaxErrorCount)
|
while (readErrorCount < RedundancyOptions.MaxErrorCount)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 发送 Ping 请求以检查设备是否在线,超时时间为 10000 毫秒
|
// 发送 Ping 请求以检查设备是否在线,超时时间为 10000 毫秒
|
||||||
online = await tcpDmtpClient.PingAsync(10000).ConfigureAwait(false);
|
online = await TcpDmtpClient.PingAsync(10000).ConfigureAwait(false);
|
||||||
if (online)
|
if (online)
|
||||||
break;
|
break;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
readErrorCount++;
|
readErrorCount++;
|
||||||
await Task.Delay(redundancy.SyncInterval, stoppingToken).ConfigureAwait(false);
|
await Task.Delay(RedundancyOptions.SyncInterval, stoppingToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// 捕获异常,增加读取错误计数器
|
// 捕获异常,增加读取错误计数器
|
||||||
readErrorCount++;
|
readErrorCount++;
|
||||||
await Task.Delay(redundancy.SyncInterval, stoppingToken).ConfigureAwait(false);
|
await Task.Delay(RedundancyOptions.SyncInterval, stoppingToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,7 +248,7 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 如果设备在线
|
// 如果设备在线
|
||||||
LogMessage?.LogTrace($"Ping ActiveStation {redundancy.MasterUri} success");
|
LogMessage?.LogTrace($"Ping ActiveStation {RedundancyOptions.MasterUri} success");
|
||||||
await StandbyAsync().ConfigureAwait(false);
|
await StandbyAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,12 +343,11 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo
|
|||||||
{
|
{
|
||||||
if (RedundancyOptions.IsMaster)
|
if (RedundancyOptions.IsMaster)
|
||||||
{
|
{
|
||||||
RedundancyTask = new DoTask(a => DoMasterWork(TcpDmtpService, RedundancyOptions.SyncInterval, LogMessage, a), LogMessage); // 创建新的任务
|
RedundancyTask = new DoTask(DoMasterWork, LogMessage); // 创建新的任务
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
RedundancyTask = new DoTask(DoSlaveWork, LogMessage); // 创建新的任务
|
||||||
RedundancyTask = new DoTask(a => DoSlaveWork(TcpDmtpClient, RedundancyOptions, a), LogMessage); // 创建新的任务
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RedundancyTask?.Start(default); // 启动任务
|
RedundancyTask?.Start(default); // 启动任务
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ internal sealed class RpcService : IRpcService
|
|||||||
public RpcService(IStringLocalizer<RpcService> localizer)
|
public RpcService(IStringLocalizer<RpcService> localizer)
|
||||||
{
|
{
|
||||||
Localizer = localizer;
|
Localizer = localizer;
|
||||||
Task.Factory.StartNew(async () => await RpcLogInsertAsync().ConfigureAwait(false), TaskCreationOptions.LongRunning);
|
Task.Factory.StartNew(RpcLogInsertAsync, TaskCreationOptions.LongRunning);
|
||||||
_rpcLogOptions = App.GetOptions<RpcLogOptions>();
|
_rpcLogOptions = App.GetOptions<RpcLogOptions>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -205,11 +205,15 @@ internal sealed class RulesEngineHostedService : BackgroundService, IRulesEngine
|
|||||||
dispatchService.Dispatch(null);
|
dispatchService.Dispatch(null);
|
||||||
|
|
||||||
|
|
||||||
_ = Task.Factory.StartNew(async () =>
|
_ = Task.Factory.StartNew(async (state) =>
|
||||||
{
|
{
|
||||||
|
if (state is not Dictionary<RulesLog, Diagram> diagrams)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
while (!cancellationToken.IsCancellationRequested)
|
while (!cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
foreach (var item in Diagrams?.Values?.SelectMany(a => a.Nodes) ?? new List<NodeModel>())
|
foreach (var item in diagrams?.Values?.SelectMany(a => a.Nodes) ?? new List<NodeModel>())
|
||||||
{
|
{
|
||||||
if (item is IExexcuteExpressionsBase)
|
if (item is IExexcuteExpressionsBase)
|
||||||
{
|
{
|
||||||
@@ -218,7 +222,7 @@ internal sealed class RulesEngineHostedService : BackgroundService, IRulesEngine
|
|||||||
}
|
}
|
||||||
await Task.Delay(60000, cancellationToken).ConfigureAwait(false);
|
await Task.Delay(60000, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false);
|
}, Diagrams, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,9 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Admin\BlazorSetParametersAsyncGenerator\BlazorSetParametersAsyncGenerator.csproj" PrivateAssets="all" OutputItemType="Analyzer" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Admin\BlazorSetParametersAsyncGenerator\BlazorSetParametersAsyncGenerator.csproj" PrivateAssets="all" OutputItemType="Analyzer" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes" Version="1.5.376.213" />
|
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes" Version="1.5.376.232" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariableMode
|
|||||||
await base.ProtectedStartAsync(cancellationToken).ConfigureAwait(false);
|
await base.ProtectedStartAsync(cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await UpdateVarModelMemory(cancellationToken).ConfigureAwait(false);
|
await UpdateVarModelMemory(cancellationToken).ConfigureAwait(false);
|
||||||
await UpdateVarModelsMemory(cancellationToken).ConfigureAwait(false);
|
await UpdateVarModelsMemory(cancellationToken).ConfigureAwait(false);
|
||||||
|
|||||||
@@ -172,8 +172,15 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel<
|
|||||||
.Map(dest => dest.Value, src => src.Value == null ? string.Empty : src.Value.ToString() ?? string.Empty)
|
.Map(dest => dest.Value, src => src.Value == null ? string.Empty : src.Value.ToString() ?? string.Empty)
|
||||||
.Map(dest => dest.CreateTime, (src) => DateTime.Now);
|
.Map(dest => dest.CreateTime, (src) => DateTime.Now);
|
||||||
|
|
||||||
|
|
||||||
|
if (_businessPropertyWithCacheInterval.BusinessUpdateEnum == BusinessUpdateEnum.Interval && _driverPropertys.IsReadDB)
|
||||||
|
{
|
||||||
|
GlobalData.VariableValueChangeEvent += VariableValueChange;
|
||||||
|
}
|
||||||
|
|
||||||
await base.InitChannelAsync(channel, cancellationToken).ConfigureAwait(false);
|
await base.InitChannelAsync(channel, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
public override Task AfterVariablesChangedAsync(CancellationToken cancellationToken)
|
public override Task AfterVariablesChangedAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
@@ -220,7 +227,7 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel<
|
|||||||
await base.ProtectedStartAsync(cancellationToken).ConfigureAwait(false);
|
await base.ProtectedStartAsync(cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (_driverPropertys.IsReadDB)
|
if (_driverPropertys.IsReadDB)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ public partial class SqlHistoryAlarm : BusinessBaseWithCacheVariableModel<Histor
|
|||||||
return base.ProtectedStartAsync(cancellationToken);
|
return base.ProtectedStartAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await Update(cancellationToken).ConfigureAwait(false);
|
await Update(cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ public partial class TDengineDBProducer : BusinessBaseWithCacheIntervalVariableM
|
|||||||
await base.ProtectedStartAsync(cancellationToken).ConfigureAwait(false);
|
await base.ProtectedStartAsync(cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await UpdateVarModelMemory(cancellationToken).ConfigureAwait(false);
|
await UpdateVarModelMemory(cancellationToken).ConfigureAwait(false);
|
||||||
await UpdateVarModelsMemory(cancellationToken).ConfigureAwait(false);
|
await UpdateVarModelsMemory(cancellationToken).ConfigureAwait(false);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public partial class Webhook : BusinessBaseWithCacheIntervalScript<VariableBasic
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override bool IsConnected() => success;
|
public override bool IsConnected() => success;
|
||||||
|
|
||||||
protected override async ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await Update(cancellationToken).ConfigureAwait(false);
|
await Update(cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public partial class KafkaProducer : BusinessBaseWithCacheIntervalScript<Variabl
|
|||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await Update(cancellationToken).ConfigureAwait(false);
|
await Update(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ public class ModbusSlave : BusinessBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override async ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
//获取设备连接状态
|
//获取设备连接状态
|
||||||
if (IsConnected())
|
if (IsConnected())
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScript<VariableBa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var clientResult = await TryMqttClientAsync(cancellationToken).ConfigureAwait(false);
|
var clientResult = await TryMqttClientAsync(cancellationToken).ConfigureAwait(false);
|
||||||
if (!clientResult.IsSuccess)
|
if (!clientResult.IsSuccess)
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ public partial class MqttCollect : CollectBase
|
|||||||
|
|
||||||
|
|
||||||
private volatile bool success;
|
private volatile bool success;
|
||||||
protected override async ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var clientResult = await TryMqttClientAsync(cancellationToken).ConfigureAwait(false);
|
var clientResult = await TryMqttClientAsync(cancellationToken).ConfigureAwait(false);
|
||||||
if (!clientResult.IsSuccess)
|
if (!clientResult.IsSuccess)
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ public partial class MqttServer : BusinessBaseWithCacheIntervalScript<VariableBa
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await Update(cancellationToken).ConfigureAwait(false);
|
await Update(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ public class OpcDaMaster : CollectBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override async ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (_driverProperties.ActiveSubscribe)
|
if (_driverProperties.ActiveSubscribe)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ public class OpcUaMaster : CollectBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TimeTick checkTimeTick = new("60000");
|
private TimeTick checkTimeTick = new("60000");
|
||||||
protected override async ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (_plc.Session == null)
|
if (_plc.Session == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ public partial class OpcUaServer : BusinessBase
|
|||||||
await base.ProtectedStartAsync(cancellationToken).ConfigureAwait(false);
|
await base.ProtectedStartAsync(cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,27 +22,27 @@
|
|||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\ThingsGateway.Foundation.OpcUa\ThingsGateway.Foundation.OpcUa.csproj" />
|
<ProjectReference Include="..\ThingsGateway.Foundation.OpcUa\ThingsGateway.Foundation.OpcUa.csproj" />
|
||||||
|
|
||||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Server" Version="1.5.376.213" GeneratePathProperty="true">
|
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Server" Version="1.5.376.232" GeneratePathProperty="true">
|
||||||
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
|
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
||||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes" Version="1.5.376.213" GeneratePathProperty="true">
|
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes" Version="1.5.376.232" GeneratePathProperty="true">
|
||||||
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
|
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
||||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="1.5.376.213" GeneratePathProperty="true">
|
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="1.5.376.232" GeneratePathProperty="true">
|
||||||
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
|
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
||||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Core" Version="1.5.376.213" GeneratePathProperty="true">
|
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Core" Version="1.5.376.232" GeneratePathProperty="true">
|
||||||
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
|
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
||||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Configuration" Version="1.5.376.213" GeneratePathProperty="true">
|
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Configuration" Version="1.5.376.232" GeneratePathProperty="true">
|
||||||
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
|
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
||||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Security.Certificates" Version="1.5.376.213" GeneratePathProperty="true">
|
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Security.Certificates" Version="1.5.376.232" GeneratePathProperty="true">
|
||||||
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
|
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public partial class RabbitMQProducer : BusinessBaseWithCacheIntervalScript<Vari
|
|||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (_channel == null)
|
if (_channel == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public partial class Synchronization : BusinessBase, IRpcDriver
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected override async ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
// /// 通讯失败时,更新设备状态,调用<see cref="DeviceRuntime.SetDeviceStatus(DateTime?, int?, string)"/>
|
// /// 通讯失败时,更新设备状态,调用<see cref="DeviceRuntime.SetDeviceStatus(DateTime?, int?, string)"/>
|
||||||
// /// <br></br>
|
// /// <br></br>
|
||||||
// /// </summary>
|
// /// </summary>
|
||||||
// protected override ValueTask ProtectedExecuteAsync(CancellationToken cancellationToken)
|
// protected override Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||||
// {
|
// {
|
||||||
// return base.ProtectedExecuteAsync(cancellationToken);
|
// return base.ProtectedExecuteAsync(cancellationToken);
|
||||||
// }
|
// }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>10.8.0</Version>
|
<Version>10.8.2</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
Reference in New Issue
Block a user