如何从 Linux 下的 ASP.NET 核心应用程序创建 PID 文件
How to create PID file from ASP.NET Core application under Linux
我写了一个 ASP.NET 核心应用程序(实际上是 .NET 5),运行 它在 Linux 下作为系统服务(在 this Microsoft guide). Then I wanted to monitor this application with monit 应用程序之后。这个应用程序需要服务来创建 PID 文件,以便它们很容易被发现。我决定写一个问答式的问题来帮助其他人更快地实现同样的目标。
注意:此处描述的解决方案是我 NuGet package with open source available on github 的一部分,以防您更喜欢通过打包方式实现目标。
IHostedService
.NET Core 中有几种方法可以 运行 后台任务。 IHostedService
是其中一个包含 StartAsync
方法的方法,该方法在注册服务后在启动时调用。该接口还定义了在正常关闭时调用的 StopAsync
。有关 IHostedService
.
的更多详细信息,请访问 this Microsoft page
知道我们可以创建自己的 IHostedService 来管理我们应用程序的 PID 文件:
public class PidFileHostedService : IHostedService
{
private readonly ILogger<PidFileHostedService> logger;
private readonly IConfiguration configuration;
private readonly IWebHostEnvironment env;
private bool isPidFileCreated = false;
private string pidFile = string.Empty;
public PidFileHostedService(ILogger<PidFileHostedService> logger,
IConfiguration configuration,
IWebHostEnvironment env)
{
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
this.env = env ?? throw new ArgumentNullException(nameof(env));
}
public async Task StartAsync(CancellationToken cancellationToken)
{
try
{
if (env.IsDevelopment())
return;
pidFile = configuration.GetValue<string>("PidFile");
if (string.IsNullOrWhiteSpace(pidFile))
return;
await WritePidFile();
isPidFileCreated = true;
}
catch (Exception ex)
{
logger.LogError(ex, $"Unexpected error when starting {nameof(PidFileHostedService)}", null);
}
}
private async Task WritePidFile()
{
var processId = Environment.ProcessId.ToString();
await File.WriteAllTextAsync(pidFile, processId);
}
public Task StopAsync(CancellationToken cancellationToken)
{
try
{
if (isPidFileCreated)
File.Delete(pidFile);
}
catch (Exception ex)
{
logger.LogError(ex, "Unexpected error when deleting PID file", null);
}
return Task.CompletedTask;
}
}
此服务假定应用程序的 appsettings.json 文件中存在 PidFile
属性。
不要忘记在 Startup.cs:
中注册服务
services.AddHostedService<PidFileHostedService>();
服务文件更改
正如我在问题中所写,我使用了 Microsoft guide on how to make my app run as a systemd service。现在,在更改之后,该服务必须对将在其中创建 PID 文件的目录具有必要的权限。可以将具有必要权限的此目录的创建委托给 systemd。将此行添加到 [Service]
部分下的服务文件中就足够了:
RuntimeDirectory=helloapp
感谢这一行,systemd 将在每个服务启动时在 /var/run
中创建 helloapp
子目录,并具有必要的权限。将以下行添加到同一部分也是一个好主意,这将告诉 systemd 在应用程序停止后仔细检查 PID 文件是否被删除:
PIDFile=/var/run/helloapp/helloapp.pid
我写了一个 ASP.NET 核心应用程序(实际上是 .NET 5),运行 它在 Linux 下作为系统服务(在 this Microsoft guide). Then I wanted to monitor this application with monit 应用程序之后。这个应用程序需要服务来创建 PID 文件,以便它们很容易被发现。我决定写一个问答式的问题来帮助其他人更快地实现同样的目标。
注意:此处描述的解决方案是我 NuGet package with open source available on github 的一部分,以防您更喜欢通过打包方式实现目标。
IHostedService
.NET Core 中有几种方法可以 运行 后台任务。 IHostedService
是其中一个包含 StartAsync
方法的方法,该方法在注册服务后在启动时调用。该接口还定义了在正常关闭时调用的 StopAsync
。有关 IHostedService
.
知道我们可以创建自己的 IHostedService 来管理我们应用程序的 PID 文件:
public class PidFileHostedService : IHostedService
{
private readonly ILogger<PidFileHostedService> logger;
private readonly IConfiguration configuration;
private readonly IWebHostEnvironment env;
private bool isPidFileCreated = false;
private string pidFile = string.Empty;
public PidFileHostedService(ILogger<PidFileHostedService> logger,
IConfiguration configuration,
IWebHostEnvironment env)
{
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
this.env = env ?? throw new ArgumentNullException(nameof(env));
}
public async Task StartAsync(CancellationToken cancellationToken)
{
try
{
if (env.IsDevelopment())
return;
pidFile = configuration.GetValue<string>("PidFile");
if (string.IsNullOrWhiteSpace(pidFile))
return;
await WritePidFile();
isPidFileCreated = true;
}
catch (Exception ex)
{
logger.LogError(ex, $"Unexpected error when starting {nameof(PidFileHostedService)}", null);
}
}
private async Task WritePidFile()
{
var processId = Environment.ProcessId.ToString();
await File.WriteAllTextAsync(pidFile, processId);
}
public Task StopAsync(CancellationToken cancellationToken)
{
try
{
if (isPidFileCreated)
File.Delete(pidFile);
}
catch (Exception ex)
{
logger.LogError(ex, "Unexpected error when deleting PID file", null);
}
return Task.CompletedTask;
}
}
此服务假定应用程序的 appsettings.json 文件中存在 PidFile
属性。
不要忘记在 Startup.cs:
services.AddHostedService<PidFileHostedService>();
服务文件更改
正如我在问题中所写,我使用了 Microsoft guide on how to make my app run as a systemd service。现在,在更改之后,该服务必须对将在其中创建 PID 文件的目录具有必要的权限。可以将具有必要权限的此目录的创建委托给 systemd。将此行添加到 [Service]
部分下的服务文件中就足够了:
RuntimeDirectory=helloapp
感谢这一行,systemd 将在每个服务启动时在 /var/run
中创建 helloapp
子目录,并具有必要的权限。将以下行添加到同一部分也是一个好主意,这将告诉 systemd 在应用程序停止后仔细检查 PID 文件是否被删除:
PIDFile=/var/run/helloapp/helloapp.pid