John S. John S. - 1 month ago 6
C# Question

How to retry windows service startup if db is offline with castle windsor and nhibernate facility?

Problem: If the DB is offline when this service is started, this service will not start as it fails inside this line:

var container = new BootStrapper().Container;
on start.

private static void Main(string[] args)
{
Logger.Info("Engine Service is bootstrapping...");
AppDomain.CurrentDomain.UnhandledException += UncaughtExceptions.DomainException;
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);

var container = new BootStrapper().Container;
var controller = container.Resolve<EngineController>();
ServiceBase.Run(controller.MainView as ServiceBase);

container.Dispose();
}


The reason it fails there is that it runs this code where it adds the nhibernate facility
container.AddFacility<NHibernateFacility>();
and fails with a connection timeout.

public void Install(IWindsorContainer container, IConfigurationStore store)
{
var isAutoTxFacilityRegistered = container.Kernel.GetFacilities().Any(f => f is AutoTxFacility);
if (!isAutoTxFacilityRegistered) container.AddFacility<AutoTxFacility>();

container.Register(
Component.For<INHibernateInstaller>().ImplementedBy<CieFluentInstaller>().IsDefault().LifestyleTransient(),
Classes.FromThisAssembly().Pick().WithService.DefaultInterfaces().LifestyleTransient()
);

var isNHibernateFacilityRegistered = container.Kernel.GetFacilities().Any(f => f is NHibernateFacility);
if (!isNHibernateFacilityRegistered) container.AddFacility<NHibernateFacility>();
}


If the windows service start up takes longer than 30 seconds (which it may if updates or backups are being conducted on the DB) the app service fails to start.

I'm using FluentNhibernate, NHibernate, Castle Windsor with NHibernateFacility.

Things I've tried:


  • Can't do it from the service start event because it fails before it
    gets to the view or controller. The view and controller have no
    direct access to the IoC container, only via an injected IoCFactory
    as per Castle Windsor recommendations.

  • I've tried to spawn a thread in the main and start it off there with
    a retry loop but because the service "waits" inside the
    ServiceBase.Run method, I can't seem to get the correct returns to
    make it "fake start" while in a retry loop.

  • Investigated lengthening the service start timeout, but can't access
    the servicebase/view since it fails before then and a system wide
    change at hundreds of production sites is not an option.



Question: How can I make it so that the windows service "starts" when DB is offline given the design?

Answer

Turned out to be a bug in NHibernate that prevented doing any of the above. Between Nibernate 2.0 and 3.0 you have to add the following to the NHibernate config (or in this case the FluentNHibernate config):

cfg.SetProperty("hbm2ddl.keywords", "none");

This allows NHibernate to properly bootstrap itself and get to the controller now without error.