如果db使用城堡windsor和nhibernate工具离线,如何重试Windows服务启动?

时间:2016-09-22 19:38:23

标签: c# nhibernate fluent-nhibernate castle-windsor

问题:如果启动此服务时数据库处于脱机状态,则此服务将无法启动,因为它在此行中失败:启动时var container = new BootStrapper().Container;

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秒(如果在数据库上进行更新或备份,可能会启动)应用程序服务无法启动。

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

我尝试过的事情:

  • 无法从服务启动事件中执行此操作,因为它在此之前失败 到达视图或控制器。视图和控制器没有 只能通过注入的IoCFactory直接访问IoC容器 根据Castle Windsor的建议。

  • 我试图在main中生成一个线程并在那里启动它 重试循环,但因为服务“等待”内部 ServiceBase.Run方法,我似乎无法得到正确的返回 在重试循环中使其成为“假启动”。

  • 调查延长了服务启动超时,但无法访问 服务库/视图,因为它在此之前和系统范围内失败 数百个生产基地的变更不是一种选择。

问题:如果设计时DB如何脱机,我怎样才能使Windows服务“启动”?

2 个答案:

答案 0 :(得分:1)

您需要将启动操作分为两类:

  1. 必须立即发生并且/或不会自行解决的行动 如果失败。诸如强制配置文件之类的东西 缺少,需要管理员干预。

  2. 我们可以延迟的行动,或者 - 更重要的是 - 可以采取的行动 由于瞬态错误而失败。这样的错误可能是网络故障或那些 我们碰巧在启动后比数据库服务器快一些 重新启动。

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

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

    主要应用程序线程的一种方法&#34;就是要遵循这个基础 结构:

    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将发出shutdownRequestedEvent信号,然后发出信号 等待RealMain线程退出。

    如果RealMain线程没有其他用途,那么设置也许应该 完成所有引导任务后,允许退出。

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

    在某些情况下可以使用的另一种方法是将引导处理为任何实际任务的依赖关系。例如,启动真实任务,真正的任务将请求数据库会话,以获得我们必须拥有会话工厂,如果我们还没有会话工厂,则启动会话工厂初始化。如果是会话工厂 无法创建,异常冒泡并且整个任务失败。剩余的 工作现在等待一段时间,然后重试任务。永远重复。

答案 1 :(得分:1)

原来是NHibernate中的一个错误,它阻止了上述任何操作。在Nibernate 2.0和3.0之间,您必须将以下内容添加到NHibernate v3.0 + config(或者在本例中为FluentNHibernate):

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

这允许NHibernate正确地自我引导并立即到达控制器而没有错误。