Skip to content

Instantly share code, notes, and snippets.

@berichan
Last active April 17, 2023 08:39
Show Gist options
  • Save berichan/f932188501c1e31c864b488f1c175ee0 to your computer and use it in GitHub Desktop.
Save berichan/f932188501c1e31c864b488f1c175ee0 to your computer and use it in GitHub Desktop.
A very simple cross-platform C# / .NET Core program that restarts an application whever it dies or every x seconds/minutes/hours/days (whatever you need really) and optionally looks out for a line in the output or console and restarts whenever it sees it after the restart period.
// This is a very simple program that takes in a config file (config.txt)
// in the same directory as the application and creates a process with
// (optional, can stay blank) arguments, and restarts it whenever it
// dies or (optionally) every x number of seconds/minutes/hours/days etc.
// You can also have it set up to look out for a certain line in the
// output and restart it whenever it sees that line (uses String.Contains)
// Can obviously be much cleaner.
// 2020 Berichan https://berichan.net/
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
namespace ProcessRestarter
{
class Program
{
private static string Commands; // all values are comma ',' separated
//executable path,args,checkalive rate (seconds),(optional) restart rate (seconds),(optional) command to look for in output before restart is called (contains)
private static string ConfigPath = Path.Combine(Directory.GetCurrentDirectory(), "config.txt");
private static Process currentRunningProcess;
private static string lastLine;
public static void Main(string[] args)
{
if (!File.Exists(ConfigPath))
{
Console.WriteLine("Rstr: No config file in this directory");
return;
}
Commands = File.ReadAllText(ConfigPath);
var split = Commands.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
if (split.Length < 3)
{
Console.WriteLine("Rstr: Invalid config format.");
return;
}
AppDomain.CurrentDomain.ProcessExit += new EventHandler(OnProcessExit);
var checkAliveRate = int.Parse(split[2]) * 1000;
var restartRate = -1;
var timer = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
if (split.Length > 3)
restartRate = int.Parse(split[3]);
var commandToLookOutFor = string.Empty;
if (split.Length > 4)
commandToLookOutFor = split[4];
currentRunningProcess = startProcessCommand(split[0], split[1]);
while (true)
{
while (!currentRunningProcess.HasExited)
{
Thread.Sleep(checkAliveRate);
if (restartRate != -1)
{
if (DateTimeOffset.UtcNow.ToUnixTimeSeconds() - timer > restartRate)
{
if (commandToLookOutFor != string.Empty)
{
Console.WriteLine($"Rstr: Waiting for line: {commandToLookOutFor}");
while (true)
{
if (lastLine.Contains(commandToLookOutFor))
{
timer = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
Console.WriteLine($"Rstr: Found {commandToLookOutFor}. Process needs to be restarted at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}. Restarting...");
currentRunningProcess.Kill();
currentRunningProcess = startProcessCommand(split[0], split[1]);
break;
}
}
}
else
{
timer = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
Console.WriteLine($"Rstr: Process needs to be restarted at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}. Restarting...");
currentRunningProcess.Kill();
currentRunningProcess = startProcessCommand(split[0], split[1]);
}
}
}
}
Console.WriteLine($"Rstr: Process dead at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}. Exit Code: ${currentRunningProcess.ExitCode} Restarting...");
currentRunningProcess = startProcessCommand(split[0], split[1]);
}
}
static Process startProcessCommand(string proc, string args)
{
var prc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = proc,
Arguments = args,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true,
RedirectStandardError = true
}
};
prc.OutputDataReceived += (p, a) =>
{
if (a.Data != null)
{
lastLine = a.Data;
Console.WriteLine(lastLine);
}
};
prc.Start();
prc.BeginOutputReadLine();
Console.WriteLine("Rstr: Started process with pid: " + prc.Id.ToString());
return prc;
}
static void OnProcessExit(object sender, EventArgs e)
{
if (currentRunningProcess != null)
if (!currentRunningProcess.HasExited)
currentRunningProcess.Kill();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment