ReadAsync internally subscribes/unsubscribes the same ScanTime tag used by the persistent probe, which was tearing down the probe subscription and triggering false reconnects every ~5s. Guard UnsubscribeInternal and stored subscription state so the probe tag is never removed by other callers. Also removes DetailedHealthCheckService (redundant with the persistent probe), adds per-instance config files (appsettings.v2.json, appsettings.v2b.json) loaded via LMXPROXY_INSTANCE env var so deploys no longer overwrite port settings. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
84 lines
3.2 KiB
C#
84 lines
3.2 KiB
C#
using System;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Serilog;
|
|
using Topshelf;
|
|
using ZB.MOM.WW.LmxProxy.Host.Configuration;
|
|
|
|
namespace ZB.MOM.WW.LmxProxy.Host
|
|
{
|
|
internal static class Program
|
|
{
|
|
static int Main(string[] args)
|
|
{
|
|
// 1. Build configuration (instance override file loaded from LMXPROXY_INSTANCE env var)
|
|
var instance = Environment.GetEnvironmentVariable("LMXPROXY_INSTANCE");
|
|
var configuration = new ConfigurationBuilder()
|
|
.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
|
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false)
|
|
.AddJsonFile($"appsettings.{instance}.json", optional: true, reloadOnChange: false)
|
|
.AddEnvironmentVariables()
|
|
.Build();
|
|
|
|
// 2. Set working directory to exe location so relative log paths resolve correctly
|
|
Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory;
|
|
|
|
// 3. Configure Serilog
|
|
Log.Logger = new LoggerConfiguration()
|
|
.ReadFrom.Configuration(configuration)
|
|
.Enrich.FromLogContext()
|
|
.Enrich.WithMachineName()
|
|
.Enrich.WithThreadId()
|
|
.CreateLogger();
|
|
|
|
try
|
|
{
|
|
// 4. Bind configuration
|
|
var config = new LmxProxyConfiguration();
|
|
configuration.Bind(config);
|
|
|
|
// 5. Configure Topshelf
|
|
var exitCode = HostFactory.Run(host =>
|
|
{
|
|
host.UseSerilog();
|
|
|
|
host.Service<LmxProxyService>(service =>
|
|
{
|
|
service.ConstructUsing(() => new LmxProxyService(config));
|
|
service.WhenStarted(s => s.Start());
|
|
service.WhenStopped(s => s.Stop());
|
|
service.WhenPaused(s => s.Pause());
|
|
service.WhenContinued(s => s.Continue());
|
|
service.WhenShutdown(s => s.Stop());
|
|
});
|
|
|
|
host.SetServiceName("ZB.MOM.WW.LmxProxy.Host");
|
|
host.SetDisplayName("SCADA Bridge LMX Proxy");
|
|
host.SetDescription("gRPC proxy for AVEVA System Platform via MXAccess COM API");
|
|
|
|
host.StartAutomatically();
|
|
host.EnablePauseAndContinue();
|
|
|
|
host.EnableServiceRecovery(recovery =>
|
|
{
|
|
recovery.RestartService(config.ServiceRecovery.FirstFailureDelayMinutes);
|
|
recovery.RestartService(config.ServiceRecovery.SecondFailureDelayMinutes);
|
|
recovery.RestartService(config.ServiceRecovery.SubsequentFailureDelayMinutes);
|
|
recovery.SetResetPeriod(config.ServiceRecovery.ResetPeriodDays);
|
|
});
|
|
});
|
|
|
|
return (int)exitCode;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Fatal(ex, "LmxProxy service terminated unexpectedly");
|
|
return 1;
|
|
}
|
|
finally
|
|
{
|
|
Log.CloseAndFlush();
|
|
}
|
|
}
|
|
}
|
|
}
|