@@ -72,16 +72,16 @@ public static IResourceBuilder<SurrealDbServerResource> AddSurrealServer(
7272 {
7373 args . Add ( "--strict" ) ;
7474 }
75-
75+
7676 // The password must be at least 8 characters long and contain characters from three of the following four sets: Uppercase letters, Lowercase letters, Base 10 digits, and Symbols
7777 var passwordParameter = password ? . Resource ?? ParameterResourceBuilderExtensions . CreateDefaultPasswordParameter ( builder , $ "{ name } -password", minLower : 1 , minUpper : 1 , minNumeric : 1 ) ;
7878
7979 string imageTag = builder . ExecutionContext . IsRunMode
8080 ? $ "{ SurrealDbContainerImageTags . Tag } -dev"
8181 : SurrealDbContainerImageTags . Tag ;
82-
82+
8383 var surrealServer = new SurrealDbServerResource ( name , userName ? . Resource , passwordParameter ) ;
84-
84+
8585 return builder . AddResource ( surrealServer )
8686 . WithEndpoint ( port : port , targetPort : SurrealDbPort , name : SurrealDbServerResource . PrimaryEndpointName )
8787 . WithImage ( SurrealDbContainerImageTags . Image , imageTag )
@@ -99,42 +99,65 @@ public static IResourceBuilder<SurrealDbServerResource> AddSurrealServer(
9999 {
100100 return ;
101101 }
102-
102+
103103 var connectionString = await surrealServer . GetConnectionStringAsync ( ct ) . ConfigureAwait ( false ) ;
104104 if ( connectionString is null )
105105 {
106106 throw new DistributedApplicationException ( $ "ResourceReadyEvent was published for the '{ surrealServer . Name } ' resource but the connection string was null.") ;
107107 }
108-
109- var options = new SurrealDbOptionsBuilder ( ) . FromConnectionString ( connectionString ) . Build ( ) ;
110- await using var surrealClient = new SurrealDbClient ( options ) ;
111-
112- foreach ( var nsResourceName in surrealServer . Namespaces . Keys )
113- {
114- if ( builder . Resources . FirstOrDefault ( n =>
115- string . Equals ( n . Name , nsResourceName , StringComparison . OrdinalIgnoreCase ) ) is
116- SurrealDbNamespaceResource surrealDbNamespace )
117- {
118- await CreateNamespaceAsync ( surrealClient , surrealDbNamespace , @event . Services , ct )
119- . ConfigureAwait ( false ) ;
120-
121- await surrealClient . Use ( surrealDbNamespace . NamespaceName , null ! , ct ) . ConfigureAwait ( false ) ;
122-
123- foreach ( var dbResourceName in surrealDbNamespace . Databases . Keys )
124- {
125- if ( builder . Resources . FirstOrDefault ( n =>
126- string . Equals ( n . Name , dbResourceName , StringComparison . OrdinalIgnoreCase ) ) is
127- SurrealDbDatabaseResource surrealDbDatabase )
128- {
129- await CreateDatabaseAsync ( surrealClient , surrealDbDatabase , @event . Services , ct )
130- . ConfigureAwait ( false ) ;
131- }
132- }
133- }
134- }
108+
109+ await EnsuresNsDbCreated ( builder , connectionString , surrealServer , @event . Services , ct ) ;
135110 } ) ;
136111 }
137112
113+ private static async Task EnsuresNsDbCreated (
114+ IDistributedApplicationBuilder builder ,
115+ string connectionString ,
116+ SurrealDbServerResource surrealServer ,
117+ IServiceProvider services ,
118+ CancellationToken ct
119+ )
120+ {
121+ var options = new SurrealDbOptionsBuilder ( ) . FromConnectionString ( connectionString ) . Build ( ) ;
122+ await using var surrealClient = new SurrealDbClient ( options ) ;
123+
124+ foreach ( var nsResourceName in surrealServer . Namespaces . Keys )
125+ {
126+ if ( builder . Resources . FirstOrDefault ( n =>
127+ string . Equals ( n . Name , nsResourceName , StringComparison . OrdinalIgnoreCase ) ) is
128+ SurrealDbNamespaceResource surrealDbNamespace )
129+ {
130+ await CreateNamespaceAsync ( surrealClient , surrealDbNamespace , services , ct )
131+ . ConfigureAwait ( false ) ;
132+
133+ // 💡 Wait until the Namespace is really created?!
134+ while ( ! ct . IsCancellationRequested )
135+ {
136+ try
137+ {
138+ await surrealClient . Use ( surrealDbNamespace . NamespaceName , null ! , ct ) . ConfigureAwait ( false ) ;
139+ break ;
140+ }
141+ catch
142+ {
143+ await Task . Delay ( 200 , ct ) . ConfigureAwait ( false ) ;
144+ }
145+ }
146+
147+ foreach ( var dbResourceName in surrealDbNamespace . Databases . Keys )
148+ {
149+ if ( builder . Resources . FirstOrDefault ( n =>
150+ string . Equals ( n . Name , dbResourceName , StringComparison . OrdinalIgnoreCase ) ) is
151+ SurrealDbDatabaseResource surrealDbDatabase )
152+ {
153+ await CreateDatabaseAsync ( surrealClient , surrealDbDatabase , services , ct )
154+ . ConfigureAwait ( false ) ;
155+ }
156+ }
157+ }
158+ }
159+ }
160+
138161 /// <summary>
139162 /// Adds a SurrealDB namespace to the application model. This is a child resource of a <see cref="SurrealDbServerResource"/>.
140163 /// </summary>
@@ -174,7 +197,7 @@ public static IResourceBuilder<SurrealDbNamespaceResource> AddNamespace(
174197 var surrealServerNamespace = new SurrealDbNamespaceResource ( name , namespaceName , builder . Resource ) ;
175198 return builder . ApplicationBuilder . AddResource ( surrealServerNamespace ) ;
176199 }
177-
200+
178201 /// <summary>
179202 /// Defines the SQL script used to create the namespace.
180203 /// </summary>
@@ -232,38 +255,34 @@ public static IResourceBuilder<SurrealDbDatabaseResource> AddDatabase(
232255 builder . Resource . AddDatabase ( name , databaseName ) ;
233256 var surrealServerDatabase = new SurrealDbDatabaseResource ( name , databaseName , builder . Resource ) ;
234257
235- SurrealDbClient ? surrealDbClient = null ;
236-
237- builder . ApplicationBuilder . Eventing . Subscribe < ConnectionStringAvailableEvent > ( surrealServerDatabase , async ( @event , ct ) =>
238- {
239- var connectionString = await surrealServerDatabase . ConnectionStringExpression . GetValueAsync ( ct ) . ConfigureAwait ( false ) ;
240- if ( connectionString is null )
241- {
242- throw new DistributedApplicationException ( $ "ConnectionStringAvailableEvent was published for the '{ surrealServerDatabase } ' resource but the connection string was null.") ;
243- }
244-
245- var options = new SurrealDbOptionsBuilder ( ) . FromConnectionString ( connectionString ) . Build ( ) ;
246- surrealDbClient = new SurrealDbClient ( options ) ;
247- } ) ;
258+ SurrealDbOptions ? surrealDbOptions = null ;
248259
249260 string namespaceName = builder . Resource . Name ;
250261 string serverName = builder . Resource . Parent . Name ;
251262
252263 string healthCheckKey = $ "{ serverName } _{ namespaceName } _{ name } _check";
253- // TODO : Bug to be fixed
254- //builder.ApplicationBuilder.Services.AddHealthChecks().AddSurreal(_ => surrealDbClient!, healthCheckKey);
255264 builder . ApplicationBuilder . Services . AddHealthChecks ( ) . Add ( new HealthCheckRegistration (
256265 name : healthCheckKey ,
257- _ => new SurrealDbHealthCheck ( surrealDbClient ! ) ,
266+ sp => new SurrealDbHealthCheck ( surrealDbOptions ! , sp . GetRequiredService < ILogger < SurrealDbHealthCheck > > ( ) ) ,
258267 failureStatus : null ,
259268 tags : null
260269 )
261270 ) ;
262-
271+
263272 return builder . ApplicationBuilder . AddResource ( surrealServerDatabase )
264- . WithHealthCheck ( healthCheckKey ) ;
273+ . WithHealthCheck ( healthCheckKey )
274+ . OnConnectionStringAvailable ( async ( _ , _ , ct ) =>
275+ {
276+ var connectionString = await surrealServerDatabase . ConnectionStringExpression . GetValueAsync ( ct ) . ConfigureAwait ( false ) ;
277+ if ( connectionString is null )
278+ {
279+ throw new DistributedApplicationException ( $ "ConnectionStringAvailableEvent was published for the '{ surrealServerDatabase } ' resource but the connection string was null.") ;
280+ }
281+
282+ surrealDbOptions = new SurrealDbOptionsBuilder ( ) . FromConnectionString ( connectionString ) . Build ( ) ;
283+ } ) ;
265284 }
266-
285+
267286 /// <summary>
268287 /// Defines the SQL script used to create the database.
269288 /// </summary>
@@ -347,7 +366,7 @@ public static IResourceBuilder<SurrealDbServerResource> WithDataBindMount(this I
347366
348367 return builder . WithBindMount ( source , "/data" ) ;
349368 }
350-
369+
351370 /// <summary>
352371 /// Copies init files into a SurrealDB container resource.
353372 /// </summary>
@@ -367,10 +386,10 @@ public static IResourceBuilder<SurrealDbServerResource> WithInitFiles(this IReso
367386 {
368387 throw new DistributedApplicationException ( $ "Unable to determine the file name for '{ source } '.") ;
369388 }
370-
389+
371390 string fileName = Path . GetFileName ( importFullPath ) ;
372391 string initFilePath = $ "{ initPath } /{ fileName } ";
373-
392+
374393 return builder
375394 . WithContainerFiles ( initPath , importFullPath )
376395 . WithEnvironment ( context =>
@@ -413,16 +432,16 @@ public static IResourceBuilder<T> WithSurrealist<T>(
413432 . WithHttpEndpoint ( targetPort : 8080 , name : "http" )
414433 . WithRelationship ( builder . Resource , "Surrealist" )
415434 . ExcludeFromManifest ( ) ;
416-
435+
417436 surrealistContainerBuilder . WithContainerFiles (
418437 destinationPath : "/usr/share/nginx/html" ,
419438 callback : async ( _ , cancellationToken ) =>
420439 {
421- var surrealDbServerInstances =
440+ var surrealDbServerInstances =
422441 builder . ApplicationBuilder . Resources . OfType < SurrealDbServerResource > ( ) . ToList ( ) ;
423- var surrealDbNamespaceResources =
442+ var surrealDbNamespaceResources =
424443 builder . ApplicationBuilder . Resources . OfType < SurrealDbNamespaceResource > ( ) . ToList ( ) ;
425- var surrealDbDatabaseResources =
444+ var surrealDbDatabaseResources =
426445 builder . ApplicationBuilder . Resources . OfType < SurrealDbDatabaseResource > ( ) . ToList ( ) ;
427446
428447 return [
@@ -431,8 +450,8 @@ public static IResourceBuilder<T> WithSurrealist<T>(
431450 Name = "instance.json" ,
432451 Contents = await WriteSurrealistInstanceJson (
433452 surrealDbServerInstances ,
434- surrealDbNamespaceResources ,
435- surrealDbDatabaseResources ,
453+ surrealDbNamespaceResources ,
454+ surrealDbDatabaseResources ,
436455 cancellationToken
437456 ) . ConfigureAwait ( false ) ,
438457 } ,
@@ -443,7 +462,7 @@ public static IResourceBuilder<T> WithSurrealist<T>(
443462
444463 return builder ;
445464 }
446-
465+
447466 private static async Task < string > WriteSurrealistInstanceJson (
448467 IList < SurrealDbServerResource > surrealDbServerInstances ,
449468 IList < SurrealDbNamespaceResource > surrealDbNamespaceResources ,
@@ -522,16 +541,16 @@ CancellationToken cancellationToken
522541 writer . WriteEndArray ( ) ;
523542
524543 writer . WriteEndObject ( ) ;
525-
544+
526545 await writer . FlushAsync ( cancellationToken ) ;
527-
546+
528547 return Encoding . UTF8 . GetString ( stream . ToArray ( ) ) ;
529548 }
530-
549+
531550 private static async Task CreateNamespaceAsync (
532- SurrealDbClient surrealClient ,
533- SurrealDbNamespaceResource namespaceResource ,
534- IServiceProvider serviceProvider ,
551+ SurrealDbClient surrealClient ,
552+ SurrealDbNamespaceResource namespaceResource ,
553+ IServiceProvider serviceProvider ,
535554 CancellationToken cancellationToken
536555 )
537556 {
@@ -543,7 +562,7 @@ CancellationToken cancellationToken
543562 try
544563 {
545564 var response = await surrealClient . RawQuery (
546- scriptAnnotation ? . Script ?? $ "DEFINE NAMESPACE IF NOT EXISTS `{ namespaceResource . NamespaceName } `;",
565+ scriptAnnotation ? . Script ?? $ "DEFINE NAMESPACE IF NOT EXISTS `{ namespaceResource . NamespaceName } `;",
547566 cancellationToken : cancellationToken
548567 ) . ConfigureAwait ( false ) ;
549568
@@ -556,11 +575,11 @@ CancellationToken cancellationToken
556575 logger . LogError ( e , "Failed to create namespace '{NamespaceName}'" , namespaceResource . NamespaceName ) ;
557576 }
558577 }
559-
578+
560579 private static async Task CreateDatabaseAsync (
561- SurrealDbClient surrealClient ,
562- SurrealDbDatabaseResource databaseResource ,
563- IServiceProvider serviceProvider ,
580+ SurrealDbClient surrealClient ,
581+ SurrealDbDatabaseResource databaseResource ,
582+ IServiceProvider serviceProvider ,
564583 CancellationToken cancellationToken
565584 )
566585 {
@@ -572,7 +591,7 @@ CancellationToken cancellationToken
572591 try
573592 {
574593 var response = await surrealClient . RawQuery (
575- scriptAnnotation ? . Script ?? $ "DEFINE DATABASE IF NOT EXISTS `{ databaseResource . DatabaseName } `;",
594+ scriptAnnotation ? . Script ?? $ "DEFINE DATABASE IF NOT EXISTS `{ databaseResource . DatabaseName } `;",
576595 cancellationToken : cancellationToken
577596 ) . ConfigureAwait ( false ) ;
578597
0 commit comments