如何重试windows服务启动,如果db是脱机城堡温莎和nhibernate设施

本文关键字:城堡 脱机 db 设施 nhibernate 如果 何重试 重试 启动 服务 windows | 更新日期: 2023-09-27 18:08:27

问题:如果该服务启动时DB离线,则该服务将无法启动,因为它在这一行内失败: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();
}

失败的原因是它运行了这段代码,其中添加了nhibernate功能container.AddFacility<NHibernateFacility>();,并且由于连接超时而失败。

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>();
}

如果windows服务启动时间超过30秒(如果在DB上进行更新或备份可能会出现这种情况),则应用程序服务启动失败。

我正在使用FluentNhibernate, NHibernate, Castle Windsor和NHibernateFacility。

我尝试过的事情:

  • 不能从服务启动事件中执行,因为它在它之前失败了到达视图或控制器。视图和控制器没有直接访问IoC容器,只能通过注入的IoCFactory

  • 我试着在主线程中生成一个线程,并在那里开始重试循环,但因为服务在内部"等待"ServiceBase。运行方法,我似乎不能得到正确的返回

  • 已调查延长服务启动超时时间,但无法访问servicebase/view,因为它在此之前失败了,并且是系统范围的

问题:我怎样才能使它,使windows服务"启动"时,DB是离线给定的设计?

如何重试windows服务启动,如果db是脱机城堡温莎和nhibernate设施

你需要把你的启动动作分为两类:

  1. 必须立即发生且/或不会自行修复的操作万一失败。诸如强制配置文件之类的东西

  2. 我们可以延迟的动作,或者更重要的是,可以延迟的动作由于瞬态错误而失败。这些错误可能是网络故障或其他我们的启动速度比数据库服务器快一些重启。

您的服务OnStart代码应该遵循以下基本结构:

OnStart:
    Perform the immediate category 1 tasks and exit if any of these fail.
    Launch the main application thread.

实现"主应用程序线程"的一种方法是遵循这个基本原则结构:

ManualResetEvent shutdownRequestedEvent = new ManualResetEvent()
RealMain:
    while (!shutdownRequestedEvent.WaitOne(0) && !bootstrapPerformed)
    {
        try
        {
            PerformBootstrap()
            bootstrapPerformed = true
        }
        catch (Exception ex)
        {
            LogError(ex)
        }
        if (!bootstrapPerformed)
            shutdownRequestedEvent.WaitOne(some timeout)
    }
    Second bootstrap action similar to above, etc.
    Third bootstrap action similar to above, etc.
    Eventually, start performing real work, while listening to 
    the shutdownRequestedEvent.

服务OnShutdown将发出shutdownrequestdevent信号,然后等待RealMain线程退出。

如果RealMain线程除了设置之外没有其他用途,它可能应该当它完成所有的引导任务时,允许退出。

另一件需要注意的事情是确保您的服务在正常运行期间能够承受由于瞬态错误而暂时失去对资源的访问。例如,您的服务不应该仅仅因为有人重新启动数据库服务器而崩溃。它应该耐心等待并永远重试。

在某些情况下可以工作的另一种方法是将引导作为实际任务的依赖项来处理。例如,启动实际任务,实际任务将请求一个数据库会话,为了获得会话,我们必须有会话工厂,如果我们还没有会话工厂,启动会话工厂初始化。如果会话工厂无法创建,就会出现异常,整个任务失败。剩下的现在的工作是等待一会儿,然后重试任务。永远重复。

原来是NHibernate的一个bug,阻止了上面的任何操作。在niberate 2.0和3.0之间,你必须在NHibernate v3.0+配置中添加以下内容(或者在本例中是FluentNHibernate):

cfg.SetProperty("hbm2ddl.keywords", "none");
这允许NHibernate正确地引导自己,现在没有错误地进入控制器。