如果 db 使用 castle windsor 和 nhibernate 设施离线,如何重试 windows 服务启动?

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

问题:如果启动此服务时数据库处于脱机状态,则此服务将不会启动,因为它在以下行中失败: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 秒(如果正在对数据库进行更新或备份,则可能会出现这种情况)应用程序服务无法启动。

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

我尝试过的事情:

问题:根据设计,我怎样才能使 windows 服务 "starts" 当 DB 离线时?

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

  1. 必须立即执行的操作 and/or 不会自行修复 万一失败。诸如强制配置文件之类的东西 缺少,需要管理员干预。

  2. 我们可以推迟的行动,或者 - 更重要的是 - 可以推迟的行动 由于瞬态错误而失败。此类错误可能是网络故障或 我们碰巧启动速度比数据库服务器快一些 重启。

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

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

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

如果 RealMain 线程除了设置之外没有其他用途,它也许应该 完成所有 bootstrap 任务后允许退出。

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

另一种在某些情况下可行的方法是将 bootstrapping 作为实际任务的依赖项来处理。比如启动real task,real task会请求一个数据库session,要知道我们必须有session factory,如果还没有session factory,就启动session factory初始化。如果会话工厂 无法创建,异常冒泡,整个任务失败。剩余的 现在的工作是稍等片刻,然后重试任务。永远重复。

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

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

这允许 NHibernate 正确地 bootstrap 自身并现在无错误地到达控制器。