I have several NServiceBus Generic Host based windows services installed on the same server as the SQL Server instance that contains my subscription storage database. When the server boots my NServiceBus Host services try to access the subscription storage database before SQL Server is up.
Here’s what I’ve tried so far:
- Added a windows server dependency on MSSQLSERVER. This did not solve the problem.
- Added a 1 minute sleep in IWantCustomInitialization.Init to verify the cause of the problem described above. This solved the problem but it’s a very crude solution.
What is the recommended way to handle this problem?
For reference find my DBSubscriptionStorageConfig and the exception that occurs when my windows services try to start below.
<DBSubscriptionStorageConfig>
<NHibernateProperties>
<add Key="connection.provider" Value="NHibernate.Connection.DriverConnectionProvider"/>
<add Key="connection.driver_class" Value="NHibernate.Driver.SqlClientDriver"/>
<add Key="connection.connection_string" Value="Data Source=.;Initial Catalog=NServiceBus;Integrated Security=SSPI"/>
<add Key="dialect" Value="NHibernate.Dialect.MsSql2008Dialect"/>
</NHibernateProperties>
</DBSubscriptionStorageConfig>
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)
I ended up creating a class which implements IWantCustomInitialization to prevent my windows services from starting before they can connect to the database. The class should probably have some logging code added but it solves my problem for now.
Here’s the code.
The config file would look like this:
Or like this: