Linux环境下自动重建并重启.NET控制台应用的问题解决
.NET控制台应用Linux环境自动重启问题解决
问题场景
在Windows开发小型.NET控制台Web服务器,部署到Amazon Linux服务器,通过GitHub Webhook触发自动拉取代码(已实现GitApi类执行git pull),后续编写Restarter类执行dotnet run实现自动重建重启,但在Linux环境下存在以下问题:
- 主进程退出后,新启动的
dotnet run进程脱离当前终端控制组 - 无法通过
Ctrl+C终止进程,只能通过端口查找并使用kill命令终止
现有代码
GitApi 类(自动拉取代码)
using System.Diagnostics; public static class GitApi { public static void Pull(string path) { Process process = new Process() { StartInfo = new ProcessStartInfo() { FileName = "git", Arguments = "pull", UseShellExecute = false, RedirectStandardOutput = true, WorkingDirectory = path } }; process.Start(); } }
Restarter 类(尝试自动重启)
using System.Diagnostics; public static class Restarter { public static void Restart(string path) { Process process = new Process() { StartInfo = new ProcessStartInfo() { FileName = "dotnet", Arguments = "run", UseShellExecute = false, WorkingDirectory = path } }; process.Start(); Environment.Exit(0); } }
解决方案
方案1:修复子进程终端关联问题
Linux下父进程退出时,子进程会被init进程接管并脱离当前终端控制组。可以通过exec命令让子进程替换父进程的shell,从而继承终端控制组,实现Ctrl+C可终止:
修改Restarter类代码:
using System.Diagnostics; public static class Restarter { public static void Restart(string path) { // 通过bash执行exec命令,让dotnet进程替换shell进程,继承终端控制组 var startInfo = new ProcessStartInfo() { FileName = "/bin/bash", Arguments = $"-c \"cd {path} && exec dotnet run\"", UseShellExecute = false, WorkingDirectory = path }; Process.Start(startInfo); Environment.Exit(0); } }
方案2:使用systemd管理服务(生产环境推荐)
通过systemd托管.NET应用,是Linux生产环境下更可靠的进程管理方案,支持自动重启、日志收集、便捷的启停命令,完全规避终端关联问题:
- 创建systemd服务文件
在/etc/systemd/system/目录下创建your-app.service(替换为你的应用名称):
[Unit] Description=你的.NET控制台Web服务器 After=network.target [Service] Type=simple User=ec2-user # 替换为运行应用的用户 WorkingDirectory=/path/to/your/app # 替换为应用根目录 ExecStart=/usr/bin/dotnet run Restart=on-failure # 进程崩溃时自动重启 RestartSec=5 # 重启间隔5秒 [Install] WantedBy=multi-user.target
- 启用并启动服务
执行以下命令:
sudo systemctl daemon-reload sudo systemctl enable your-app.service sudo systemctl start your-app.service
- 修改Webhook重启逻辑
将Restarter类改为调用systemd重启命令:
using System.Diagnostics; public static class Restarter { public static void Restart() { var process = new Process() { StartInfo = new ProcessStartInfo() { FileName = "sudo", Arguments = "systemctl restart your-app.service", UseShellExecute = false, RedirectStandardOutput = true } }; process.Start(); process.WaitForExit(); // 等待命令执行完成 } }
- 配置sudo免密权限
为运行Webhook服务的用户配置免密执行systemctl命令,避免输入密码:
执行sudo visudo,添加以下内容:
ec2-user ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart your-app.service
(替换ec2-user为你的用户,your-app.service为服务名称)
额外注意事项
- 确保运行Webhook服务的用户拥有
git pull的权限(可配置SSH密钥免密拉取) - 使用
dotnet run仅适合开发/测试环境,生产环境建议先发布应用(dotnet publish),然后运行发布后的可执行文件,修改systemd的ExecStart路径为发布后的文件路径
内容的提问来源于stack exchange,提问作者fyrkantis
相关产品推荐
相关产品推荐

