NServiceBus HostベースのWindowsサービスをSQL Serverが起動するまで待機させるにはどうすればよいですか?

私はサブスクリプションストレージデータベースを含むSQL Serverインスタンスと同じサーバーに複数のNServiceBus Generic HostベースのWindowsサービスをインストールしています。サーバーがNServiceBusホストサービスを起動すると、SQL Serverが起動する前にサブスクリプションストレージデータベースにアクセスしようとします。

これまで私が試したことは次のとおりです。

  1. MSSQLSERVERにWindowsサーバーの依存関係を追加しました。これで問題は解決されませんでした。
  2. IWantCustomInitialization.Initに1分のスリープを追加して、上記の問題の原因を確認します。これは問題を解決しましたが、非常に粗末な解決策です。

この問題を処理するには、どのような方法が推奨されますか?

参考までに、私のDBSubscriptionStorageConfigと、Windowsサービスが以下で開始しようとしたときに発生する例外を見つけてください。



  
  
  
    




ERROR NHibernate.Tool.hbm2ddl.SchemaUpdate [(null)] <(null)> - could not get database metadata
System.Data.SqlClient.SqlException (0x80131904): Cannot open database "NServiceBus" requested by the login. The login failed.
Login failed for user 'SE1\fooservice'.
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler,            
SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlInternalConnectionTds.CompleteLogin(Boolean enlistOK)
at System.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, Boolean redirectedUserInstance, SqlConnection owningObject, SqlConnectionString connectionOptions, TimeoutTimer timeout)
at System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(SqlConnection owningObject,     
TimeoutTimer timeout, SqlConnectionString connectionOptions, String newPassword, Boolean redirectedUserInstance)
at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity,         
SqlConnectionString connectionOptions, Object providerInfo, String newPassword, SqlConnection owningObject, Boolean redirectedUserInstance)
at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options,       
Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection)
at System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnection owningConnection, DbConnectionPool pool, DbConnectionOptions options)
at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject)
at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject)
at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection,       
DbConnectionFactory connectionFactory)
at System.Data.SqlClient.SqlConnection.Open()
at NHibernate.Connection.DriverConnectionProvider.GetConnection()
at NHibernate.Tool.hbm2ddl.ManagedProviderConnectionHelper.Prepare()
at NHibernate.Tool.hbm2ddl.SchemaUpdate.Execute(Action`1 scriptAction, Boolean doUpdate)
2
マイクロソフトに任せて、「まさに私が探していたものだが、期待したとおりにはうまくいかない」というソリューションをもう一度提供してください。
追加された 著者 Udi Dahan,
うーん、私はトリックを行うmsmsqlへの依存を期待していたでしょうか、あなたはそれが正しくセットアップされていますか?
追加された 著者 Andreas Öhlund,
@ AndreasÖhlund:残念ながらそれは動作しません。これをチェックしてくださいリンク
追加された 著者 Joe,

2 答え

私はIWantCustomInitializationを実装するクラスを作成して、Windowsサービスがデータベースに接続する前に起動しないようにしました。クラスにはおそらくいくつかのログコードが追加されるはずですが、今のところ私の問題を解決します。

ここにコードがあります。

public class DbDependencyChecker : IWantCustomInitialization
{
    private const int ConnectionRetries = 15;
    private const int TimeBetweenRetries = 60000;      
    private const string DefaultConnectionName = "DbDependency";
    private const string CustomConnectionNameKey = "DbDependencyConnectionName";

    public void Init()
    {
        var connectionName = ConfigurationManager.AppSettings[CustomConnectionNameKey];
        if (string.IsNullOrWhiteSpace(connectionName))
            connectionName = DefaultConnectionName;
        var providerName = ConfigurationManager.ConnectionStrings[connectionName].ProviderName;
        var connectionString = ConfigurationManager.ConnectionStrings[connectionName].ConnectionString;

        if (string.IsNullOrWhiteSpace(providerName) || string.IsNullOrWhiteSpace(connectionString))
            return;

        for (var i = 0; i < ConnectionRetries; i++)
        {
            if (TryToConnect(providerName, connectionString))
                break;
            System.Threading.Thread.Sleep(TimeBetweenRetries);
        }
    }

    private static bool TryToConnect(string providerName, string connectionString)
    {
        try
        {
            using (var connection = CreateConnection(providerName, connectionString))
            {
                connection.Open();
            }
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }

    private static IDbConnection CreateConnection(string providerName, string connectionString)
    {
        var provider = DbProviderFactories.GetFactory(providerName);
        var connection = provider.CreateConnection();
        connection.ConnectionString = connectionString;
        return connection;
    }        
}

設定ファイルは次のようになります。


  



  

または次のように:


      

2
追加された

自動(遅延開始)のWindowsサービスのスタートアップの種類を使用していますか?完全に遅れが必要だとは思っていませんでした。これはアプリケーション内部にあるものよりも少し望ましいかもしれません(特に、あなたがいつか別のマシンにデータベースを持っていて、そこでSQLサーバーを実行していない場合)。

0
追加された
私はもっ​​と頑強なものを求めていたので、遅れてスタートしなかった。
追加された 著者 Joe,