新增: 新增网关冗余的数据同步使能配置项,关闭后不再同步数据

This commit is contained in:
Diego
2026-03-09 17:27:36 +08:00
parent 88499d09d2
commit 49fad48f8f
18 changed files with 176 additions and 46 deletions
+9 -20
View File
@@ -13,14 +13,14 @@
CS8002;NU1510;SYSLIB5007;CS8603;CS8618;CS1591;CS8625;CS8602;CS8604;CS8600;CS8601;CS8714;CS8619;CS8629;CS8765;CS8634;CS8621;CS8767;CS8633;CS8620;CS8610;CS8631;CS8605;CS8622;CS8613;NU5100;NU5104;NU1903;NU1902;CA1863;CA1812;CA1805;CA1515;CA1508;CA1819;CA1852;CA5394;CA1822;CA1815;CA1813;CA5358;CA5384;CA5400;CA5401;CA1814;CA1835;CA5392;CA5350;CA2100;CA1848;CA1810;CA1513;CA5351;CA1510;CA1512;CA1823;RCS1102;RCS1194;NETSDK1206
</NoWarn>
<TouchSocketVersion>4.1.7</TouchSocketVersion>
<AdminVersion>12.4.56</AdminVersion>
<FoundationVersion>12.4.71</FoundationVersion>
<PluginVersion>12.4.57</PluginVersion>
<ProPluginVersion>12.4.47</ProPluginVersion>
<GatewayVersion>12.4.96</GatewayVersion>
<AdminVersion>12.4.57</AdminVersion>
<FoundationVersion>12.4.72</FoundationVersion>
<PluginVersion>12.4.58</PluginVersion>
<ProPluginVersion>12.4.48</ProPluginVersion>
<GatewayVersion>12.4.97</GatewayVersion>
<Version>$(GatewayVersion)</Version>
<ManagementVersion>12.4.41</ManagementVersion>
<ManagementVersion>12.4.42</ManagementVersion>
<LangVersion>preview</LangVersion>
@@ -30,12 +30,11 @@
<NET8Version>8.0.24</NET8Version>
<SatelliteResourceLanguages>zh-Hans;en-US</SatelliteResourceLanguages>
<!--设置为 true时,删除特定于全球化的代码和数据。 有关详细信息,请参阅固定模式。-->
<InvariantGlobalization>false</InvariantGlobalization>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' != 'net8.0' ">
<PluginTargetFramework>net10.0</PluginTargetFramework>
</PropertyGroup>
@@ -45,30 +44,20 @@
<PropertyGroup>
<AnalysisModeDesign>None</AnalysisModeDesign>
<AnalysisModeDocumentation>All</AnalysisModeDocumentation>
<AnalysisModeGlobalization>None</AnalysisModeGlobalization>
<AnalysisModeInteroperability>All</AnalysisModeInteroperability>
<AnalysisModeMaintainability>All</AnalysisModeMaintainability>
<AnalysisModeNaming>None</AnalysisModeNaming>
<AnalysisModePerformance>All</AnalysisModePerformance>
<AnalysisModeSingleFile>All</AnalysisModeSingleFile>
<AnalysisModeReliability>All</AnalysisModeReliability>
<AnalysisModeSecurity>All</AnalysisModeSecurity>
<AnalysisModeUsage>None</AnalysisModeUsage>
<AnalysisModeStyle>None</AnalysisModeStyle>
</PropertyGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)Directory.Build.props" Pack="true" PackagePath="\" />
<None Include="$(MSBuildThisFileDirectory)Directory.Build.props" Pack="false" PackagePath="\" />
</ItemGroup>
<PropertyGroup>
<DebugSymbols>True</DebugSymbols>
<DebugType>Embedded</DebugType>
<EmbedAllSources>True</EmbedAllSources>
</PropertyGroup>
+76
View File
@@ -0,0 +1,76 @@
<Project>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)Directory.Build.targets" Pack="false" PackagePath="\" />
</ItemGroup>
<PropertyGroup Condition="($([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0')) OR $([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net10.0'))) AND '$(EnableAot)' == 'true'">
<!--AOT 兼容性分析器-->
<IsAotCompatible>true</IsAotCompatible>
<IsTrimmable>true</IsTrimmable>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
<EnableSingleFileAnalyzer>true</EnableSingleFileAnalyzer>
<EnableAotAnalyzer>true</EnableAotAnalyzer>
<!--本机调试信息-->
<StripSymbols>true</StripSymbols>
<!--编译器选择混合方法:生成快速代码,或优先考虑可执行文件的大小-->
<!--<OptimizationPreference>Speed</OptimizationPreference>-->
<OptimizationPreference>Speed</OptimizationPreference>
<!--设置为 false时,将删除对解析非文件 URL System.Xml的支持。 仅支持文件系统解析。-->
<XmlResolverIsNetworkingEnabledByDefault>false</XmlResolverIsNetworkingEnabledByDefault>
<!--设置为 true时,将去除程序集的 System.* 异常消息。 从 System.* 程序集引发异常时,该消息是简化的资源 ID,而不是完整消息-->
<UseSystemResourceKeys>true</UseSystemResourceKeys>
<!--设置为 true时,使用 Android 和 iOS 的默认平台实现 HttpMessageHandler 并删除托管实现。-->
<UseNativeHttpHandler>true</UseNativeHttpHandler>
<!--如果设置为true ,则删除 LINQ 中的某些吞吐量优化,以免对应用程序的大小产生不利影响-->
<UseSizeOptimizedLinq>false</UseSizeOptimizedLinq>
<!--设置为 false时,删除运行时生成堆栈跟踪(例如或 Environment.StackTraceException.ToString)的支持。 从堆栈跟踪字符串中删除的信息量可能取决于其他部署选项。 此选项不会影响调试器生成的堆栈跟踪。-->
<StackTraceSupport>true</StackTraceSupport>
<!--设置为 false时,删除对检测的支持 System.Diagnostics.Metrics 。-->
<MetricsSupport>false</MetricsSupport>
<!--设置为 false时,删除与热重载相关的元数据更新特定逻辑。-->
<MetadataUpdaterSupport>false</MetadataUpdaterSupport>
<!--设置为 true时,删除特定于全球化的代码和数据。 有关详细信息,请参阅固定模式。-->
<InvariantGlobalization>false</InvariantGlobalization>
<!--设置为 false时,删除与诊断支持 System.Net.Http相关的代码。-->
<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
<!--设置为 false时,删除与对 HTTP/3 的支持 System.Net.Http相关的代码。-->
<Http3Support>false</Http3Support>
<!--设置为 false时,删除与 EventSource 相关的代码和逻辑。-->
<EventSourceSupport>false</EventSourceSupport>
<!--设置为 false后,删除不安全的 UTF-7 编码代码。 有关详细信息,请参阅 UTF-7 代码路径已过时。-->
<EnableUnsafeUTF7Encoding>false</EnableUnsafeUTF7Encoding>
<!--设置为 false时,删除 BinaryFormatter 序列化支持。 有关详细信息,请参阅 BinaryFormatter 序列化方法已过时 , 并且已删除内置 BinaryFormatter 实现,并且始终引发。-->
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
<!--设置为 false时,删除支持更好的调试体验的代码。 此设置还会删除符号。-->
<DebuggerSupport>false</DebuggerSupport>
<!--设置为 false时,删除在受支持的平台上创建 自动发布池 的代码。 false 是 .NET SDK 的默认值。-->
<AutoreleasePoolSupport>false</AutoreleasePoolSupport>
</PropertyGroup>
</Project>
+32 -14
View File
@@ -1,4 +1,9 @@
<Project>
<PropertyGroup Condition="'$(DisableDebugSymbols)' != 'true'">
<DebugSymbols>True</DebugSymbols>
<DebugType>Embedded</DebugType>
<EmbedAllSources>True</EmbedAllSources>
</PropertyGroup>
<PropertyGroup>
@@ -11,18 +16,32 @@
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)ThingsGateway.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<!--Condition="'$(Configuration)' == 'Release'"-->
<PropertyGroup>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)PackNuget.props" Pack="false" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)README.md" Pack="true" PackagePath="\" />
<None Include="$(MSBuildThisFileDirectory)LICENSE" Pack="true" PackagePath="\" />
<None Include="$(MSBuildThisFileDirectory)icon.png" Pack="true" PackagePath="\" />
<None Include="$(MSBuildThisFileDirectory)logo.svg" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Roslynator.Analyzers" Version="4.15.0">
<PrivateAssets>all</PrivateAssets>
@@ -35,16 +54,15 @@
</PackageReference>
</ItemGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)PackNuget.props" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)README.md" Pack="true" PackagePath="\" />
<None Include="$(MSBuildThisFileDirectory)LICENSE" Pack="true" PackagePath="\" />
<None Include="$(MSBuildThisFileDirectory)icon.png" Pack="true" PackagePath="\" />
<None Include="$(MSBuildThisFileDirectory)logo.svg" Pack="true" PackagePath="\" />
</ItemGroup>
</Project>
+3 -3
View File
@@ -1,5 +1,5 @@
<Solution>
<Folder Name="/Benchmark/" />
<Folder Name="/benchmark/" />
<Folder Name="/src/">
<Project Path="src/ThingsGateway.Foundation.Razor/ThingsGateway.Foundation.Razor.csproj" />
<Project Path="src/ThingsGateway.Gateway.Application/ThingsGateway.Gateway.Application.csproj" />
@@ -8,10 +8,10 @@
<Project Path="src/ThingsGateway.Management.Application/ThingsGateway.Management.Application.csproj" />
<Project Path="src/ThingsGateway.Management.Razor/ThingsGateway.Management.Razor.csproj" />
</Folder>
<Folder Name="/Test/">
<Folder Name="/test/">
<Project Path="test/ThingsGateway.Gateway.Test/ThingsGateway.Gateway.Test.csproj" />
</Folder>
<Folder Name="/解决方案项/">
<Folder Name="/props/">
<File Path=".gitignore" />
<File Path="Directory.Build.props" />
<File Path="PackNuget.props" />
@@ -15,7 +15,6 @@ using Microsoft.Extensions.Localization;
using ThingsGateway.Foundation;
using ThingsGateway.Foundation.Common;
using ThingsGateway.Foundation.Common.Extension;
using ThingsGateway.Foundation.Common.Json.Extension;
using TouchSocket.Core;
@@ -14,6 +14,7 @@ using Riok.Mapperly.Abstractions;
using System.Collections.Concurrent;
using System.ComponentModel.DataAnnotations;
using ThingsGateway.Foundation.Common.Json.Extension;
namespace ThingsGateway.Gateway.Application;
@@ -135,6 +135,7 @@
"Status": "Current Site Status",
"Switch": "Switch",
"SyncInterval": "Data Synchronization Interval",
"SyncEnable": "Enable Data Synchronization",
"VerifyToken": "Verification Token"
},
"ThingsGateway.Gateway.Application.RedundancyService": {
@@ -134,6 +134,7 @@
"Status": "当前站点状态",
"Switch": "切换",
"SyncInterval": "数据同步间隔",
"SyncEnable": "数据同步使能",
"VerifyToken": "验证令牌"
},
"ThingsGateway.Gateway.Application.RedundancyService": {
@@ -14,6 +14,7 @@ using Riok.Mapperly.Abstractions;
using System.Collections.Concurrent;
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Nodes;
using ThingsGateway.Foundation.Common.Json.Extension;
using ThingsGateway.Gateway.Application.Extensions;
#if !Management
@@ -71,7 +71,15 @@
"Code": "3000",
"IsDelete": "0",
"SortCode": 99
},
{
"Id": 234511701160015,
"DictType": "System",
"Category": "RedundancyOptions",
"Name": "SyncEnable",
"Code": "true",
"IsDelete": "0",
"SortCode": 99
}
]
}
@@ -63,4 +63,9 @@ public class RedundancyOptions
/// </summary>
[MinValue(1000)]
public int SyncInterval { get; set; }
/// <summary>
/// 获取或设置开启冗余数据同步。
/// </summary>
public bool SyncEnable { get; set; } = true;
}
@@ -39,6 +39,7 @@ internal sealed class RedundancyService : BaseService<SysDict>, IRedundancyServi
new SysDict() { DictType = DictTypeEnum.System, Category = nameof(RedundancyOptions), Name = nameof(RedundancyOptions.MaxErrorCount), Code = input.MaxErrorCount.ToString() },
new SysDict() { DictType = DictTypeEnum.System, Category = nameof(RedundancyOptions), Name = nameof(RedundancyOptions.IsStartBusinessDevice), Code = input.IsStartBusinessDevice.ToString() },
new SysDict() { DictType = DictTypeEnum.System, Category = nameof(RedundancyOptions), Name = nameof(RedundancyOptions.SyncInterval), Code = input.SyncInterval.ToString() },
new SysDict() { DictType = DictTypeEnum.System, Category = nameof(RedundancyOptions), Name = nameof(RedundancyOptions.SyncEnable), Code = input.SyncEnable.ToString() },
};
var storageable = await db.Storageable(dicts).WhereColumns(it => new { it.DictType, it.Category, it.Name }).ToStorageAsync().ConfigureAwait(false);
@@ -77,6 +78,7 @@ internal sealed class RedundancyService : BaseService<SysDict>, IRedundancyServi
redundancy.MaxErrorCount = sysDicts.FirstOrDefault(a => a.Category == nameof(RedundancyOptions) && a.Name == nameof(RedundancyOptions.MaxErrorCount))?.Code.ToInt() ?? 3000;
redundancy.IsStartBusinessDevice = sysDicts.FirstOrDefault(a => a.Category == nameof(RedundancyOptions) && a.Name == nameof(RedundancyOptions.IsStartBusinessDevice))?.Code.ToBoolean() ?? false;
redundancy.SyncInterval = sysDicts.FirstOrDefault(a => a.Category == nameof(RedundancyOptions) && a.Name == nameof(RedundancyOptions.SyncInterval))?.Code.ToInt() ?? 30000;
redundancy.SyncEnable = sysDicts.FirstOrDefault(a => a.Category == nameof(RedundancyOptions) && a.Name == nameof(RedundancyOptions.SyncEnable))?.Code.ToBoolean() ?? true;
App.CacheService.Set(key, redundancy);
}
@@ -66,6 +66,26 @@ internal sealed class RedundancyTask : IRpcDriver, IAsyncDisposable
? highMemorySize
: defaultSize;
}
private IEnumerable<DeviceDataWithValue> GetDeviceDataWithValues(IEnumerable<VariableRuntime> variableBasicDatas)
{
foreach (var item in variableBasicDatas.GroupBy(a => a.DeviceId))
{
if (GlobalData.IdDevices.TryGetValue(item.Key, out var device))
{
DeviceDataWithValue deviceDataWithValue = new();
deviceDataWithValue.ActiveTime = device.ActiveTime;
deviceDataWithValue.DeviceStatus = device.DeviceStatus;
deviceDataWithValue.LastErrorMessage = device.LastErrorMessage;
deviceDataWithValue.Name = device.Name;
deviceDataWithValue.ReadOnlyVariableRuntimes = item.ToDictionary(a => a.Name, a => a.AdaptVariableDataWithValue());
yield return deviceDataWithValue;
}
}
}
/// <summary>
/// 主站
/// </summary>
@@ -73,6 +93,8 @@ internal sealed class RedundancyTask : IRpcDriver, IAsyncDisposable
{
try
{
if (!RedundancyOptions.SyncEnable) return;
bool online = false;
var waitInvoke = CreateDmtpInvokeOption(stoppingToken);
@@ -86,16 +108,22 @@ internal sealed class RedundancyTask : IRpcDriver, IAsyncDisposable
// 如果 online 为 true,表示设备在线
if (online)
{
int batchSize = 50;
var deviceRunTimes = GlobalData.ReadOnlyIdDevices.Where(a => a.Value.IsCollect == true).Select(a => a.Value).Concat([GlobalData.MemoryDeviceRuntime]).Batch(batchSize);
var batchSize = GetBatchSize();
var variableBasicDatas = GlobalData.GetEnableVariables();
var deviceRunTimes = variableBasicDatas.ChunkBetter(batchSize);
var dataChunks = deviceRunTimes
.Select(chunk => GetDeviceDataWithValues(chunk).ToList())
.Where(data => data.Count > 0)
;
foreach (var item in _tcpDmtpService.Clients)
{
foreach (var deviceDataWithValues in deviceRunTimes)
foreach (var deviceDataWithValues in dataChunks)
{
// 将 GlobalData.CollectDevices 和 GlobalData.Variables 同步到从站
await item.GetDmtpRpcActor().UpDataAsync(deviceDataWithValues.AdaptListDeviceDataWithValue(), waitInvoke).ConfigureAwait(false);
await item.GetDmtpRpcActor().UpDataAsync(deviceDataWithValues, waitInvoke).ConfigureAwait(false);
}
LogMessage?.LogTrace($"{item.Id} Update StandbyStation data success");
}
@@ -18,6 +18,7 @@ using ThingsGateway.Blazor.Diagrams.Core;
using ThingsGateway.Blazor.Diagrams.Core.Anchors;
using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using ThingsGateway.Blazor.Diagrams.Core.Models;
using ThingsGateway.Foundation.Common.Json.Extension;
namespace ThingsGateway.Gateway.Application;
@@ -1,4 +1,5 @@
using System.Text.Json.Nodes;
using ThingsGateway.Foundation.Common.Json.Extension;
namespace ThingsGateway.Gateway.Application;
@@ -1,4 +1,5 @@
using System.Text.Json.Nodes;
using ThingsGateway.Foundation.Common.Json.Extension;
namespace ThingsGateway.Gateway.Application;
@@ -9,7 +9,7 @@
<ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
<PackageReference Include="Riok.Mapperly" Version="4.3.1" ExcludeAssets="runtime" PrivateAssets="all" />
<PackageReference Include="Rougamo.Fody" Version="5.0.2" />
<PackageReference Include="TouchSocket.Dmtp" Version="$(TouchSocketVersion)" />
<PackageReference Include="TouchSocket.WebApi" Version="$(TouchSocketVersion)" />
@@ -12,8 +12,6 @@ using Microsoft.AspNetCore.ResponseCompression;
using System.Runtime.InteropServices;
using System.Text;
using ThingsGateway.Admin.Application;
using ThingsGateway.Common;
using ThingsGateway.DB;
using ThingsGateway.Foundation.Common;