Skip to content

Instantly share code, notes, and snippets.

@ikalafat
Last active February 27, 2021 17:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ikalafat/33c1e41cd42a89263193cbf221292f93 to your computer and use it in GitHub Desktop.
Save ikalafat/33c1e41cd42a89263193cbf221292f93 to your computer and use it in GitHub Desktop.
Hangfire Shutdown Issues - example
Startup code in Program.cs:
private static async Task Main()
{
#if DEBUG && !DEV
System.Threading.Thread.Sleep(10 * 1000);
#endif
log4net.Config.XmlConfigurator.Configure();
Hierarchy h = (Hierarchy)log4net.LogManager.GetRepository();
rootLogger = h.Root;
try
{
rootLogger.Log(Level.Info, "XXXX Windows Service Host", null);
var kernel = await CreateKernel();
rootLogger.Log(Level.Info, "XXXX Windows Service Host - Kernel created.", null);
bootstrapper.Initialize(() => kernel);
rootLogger.Log(Level.Info, "XXXX Windows Service Host - Bootstrapper initialized.", null);
try
{
ServiceBase.Run(bootstrapper.Kernel.GetAll<ServiceBase>().ToArray());
}
catch (Exception ex)
{
rootLogger.Log(Level.Error, "Unhandled error.", ex);
throw;
}
finally
{
bootstrapper.ShutDown();
}
rootLogger.Log(Level.Info, "XXXX Windows Service Host - Stopped", null);
kernel.Dispose();
}
catch (Exception ex)
{
rootLogger.Log(Level.Error, "XXXX Windows Service Host - Service lifecyle", ex);
throw;
}
//Environment.Exit(0);
}
My service is bounded:
kernel.Bind<ServiceBase>().To<Service>();
It inherits ServiceBase class.
OnStart code in Service.cs:
protected override void OnStart(string[] args)
{
try
{
foreach (var host in this.hosts)
{
host.StartAsync(args).ContinueWith(t =>
{
if (t.IsCanceled)
{
Logger.Info("Host start canceled, gracefully shutting down service.");
this.Stop();
}
else if (t.IsFaulted)
{
Logger.ErrorException("Fatal error. Shutting down service.", t.Exception);
this.Stop();
}
});
}
}
catch (System.Exception ex)
{
Logger.ErrorException("Error in service startup.", ex);
throw;
}
}
"hosts" is array of sub-services which are called and started (usually one or two services in my case) that implement my IApplicationConsoleHost interface and they have StartAsync and StopAsync methods.
OnStop:
protected override void OnStop()
{
try
{
RequestAdditionalTime(30000); //Make sure that all tasks have finished
foreach (var host in this.hosts)
{
host.StopAsync().Wait();
}
}
catch (System.Exception ex)
{
Logger.ErrorException("Error in service stop.", ex);
throw;
}
}
In my case, in my implementation of IApplicationConsoleHost, StartAsync contains SchedulerServer startup and job registration logic, while StopAsync shuts down the scheduler server.
Implementations of IApplicationConsoleHost are bound as singleton.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment