@@ -376,7 +376,7 @@ internal static string GetResourceType<T>(T resource, IResource appModelResource
376376 Task IDcpObjectFactory . UpdateWithEffectiveAddressInfo ( IEnumerable < Service > services , CancellationToken cancellationToken , TimeSpan ? timeout )
377377 => UpdateWithEffectiveAddressInfo ( services , cancellationToken , timeout ) ;
378378
379- // Watches DCP object updates via a Kubernetes watch wrapped in the supplied retry pipeline,
379+ // Watches DCP object updates via a Kubernetes watch wrapped in the supplied retry pipeline,
380380 // till all objects reach desired state or a timeout occurs.
381381 // Returns names of objects that did not reach the desired state.
382382 private async Task < HashSet < string > > WatchUntilDesiredStateAsync < TDcpResource > (
@@ -591,8 +591,8 @@ private Task CreateAllDcpObjectsAsync<RT>(CancellationToken cancellationToken) w
591591 Task IDcpObjectFactory . CreateDcpObjectsAsync < T > ( IEnumerable < T > objects , CancellationToken cancellationToken )
592592 => CreateDcpObjectsAsync ( objects , cancellationToken ) ;
593593
594- async Task < T > IDcpObjectFactory . PatchDcpObjectAsync < T > ( T obj , Action < T > change , CancellationToken cancellationToken )
595- => await PatchDcpObjectAsync ( obj , change , cancellationToken ) . ConfigureAwait ( false ) ;
594+ Task < T > IDcpObjectFactory . PatchDcpObjectAsync < T > ( T obj , Action < T > change , CancellationToken cancellationToken )
595+ => PatchDcpObjectAsync ( obj , change , cancellationToken ) ;
596596
597597 private async Task < T > PatchDcpObjectAsync < T > ( T obj , Action < T > change , CancellationToken cancellationToken )
598598 where T : CustomResource , IKubernetesStaticMetadata
@@ -1071,20 +1071,25 @@ public async Task StartResourceAsync(IResourceReference resourceReference, Cance
10711071 await appResource . Initialized . WaitAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
10721072 using var _ = await ConcurrencyUtils . AcquireAllAsync ( [ appResource . SerializedOpSemaphore ] , cancellationToken ) . ConfigureAwait ( false ) ;
10731073
1074- if ( await TryStartCreatedDelayedStartResourceAsync ( resourceReference , resourceType , cancellationToken ) . ConfigureAwait ( false ) )
1074+ // For resources that need delete/recreate startup, raise the starting event after deletion. This is required because
1075+ // deleting the existing DCP object temporarily overrides the status with a terminal state, such as "Exited".
1076+ switch ( resourceReference )
10751077 {
1076- return ;
1077- }
1078+ // We need to handle explicit start persistent resources specially on first launch as they may already be running, so we need to register them with DCP to discover their status.
1079+ case RenderedModelResource < Container > { DcpResource . Spec . Start : false } cr when ! DcpModelUtilities . ShouldDeferCreateForExplicitStart ( cr . ModelResource , cr . DcpResource . Spec . Start ) :
1080+ await PublishConnectionStringAvailableEventAsync ( cr . ModelResource , cancellationToken ) . ConfigureAwait ( false ) ;
1081+ await _executorEvents . PublishAsync ( new OnResourceStartingContext ( cancellationToken , resourceType , cr . ModelResource , cr . DcpResourceName ) ) . ConfigureAwait ( false ) ;
1082+ await PatchDcpObjectAsync ( cr . DcpResource , static c => c . Spec . Start = true , cancellationToken ) . ConfigureAwait ( false ) ;
1083+ break ;
10781084
1079- // Reset cached callback results so they are re-evaluated on restart.
1080- ForgetCachedCallbackResults ( resourceReference . ModelResource ) ;
1085+ case RenderedModelResource < Executable > { DcpResource . Spec . Start : false } er when ! DcpModelUtilities . ShouldDeferCreateForExplicitStart ( er . ModelResource , er . DcpResource . Spec . Start ) :
1086+ await PublishConnectionStringAvailableEventAsync ( er . ModelResource , cancellationToken ) . ConfigureAwait ( false ) ;
1087+ await _executorEvents . PublishAsync ( new OnResourceStartingContext ( cancellationToken , resourceType , er . ModelResource , er . DcpResourceName ) ) . ConfigureAwait ( false ) ;
1088+ await PatchDcpObjectAsync ( er . DcpResource , static e => e . Spec . Start = true , cancellationToken ) . ConfigureAwait ( false ) ;
1089+ break ;
10811090
1082- // Raise event after resource has been deleted. This is required because the event sets the status to "Starting" and resources being
1083- // deleted will temporarily override the status to a terminal state, such as "Exited".
1084- switch ( resourceReference )
1085- {
10861091 case RenderedModelResource < Container > cr :
1087- await EnsureResourceDeletedAsync < Container > ( resourceReference . DcpResourceName , cancellationToken ) . ConfigureAwait ( false ) ;
1092+ await EnsureResourceDeletedAsync < Container > ( resourceReference , cancellationToken ) . ConfigureAwait ( false ) ;
10881093
10891094 // Ensure we explicitly start the container even if original container was created in "delay-start" mode.
10901095 cr . DcpResource . Spec . Start = true ;
@@ -1095,7 +1100,7 @@ public async Task StartResourceAsync(IResourceReference resourceReference, Cance
10951100 await _containerCreator . CreateObjectAsync ( cr , cctx , resourceLogger , this , cancellationToken ) . ConfigureAwait ( false ) ;
10961101 break ;
10971102 case RenderedModelResource < Executable > er :
1098- await EnsureResourceDeletedAsync < Executable > ( resourceReference . DcpResourceName , cancellationToken ) . ConfigureAwait ( false ) ;
1103+ await EnsureResourceDeletedAsync < Executable > ( resourceReference , cancellationToken ) . ConfigureAwait ( false ) ;
10991104
11001105 // Ensure we explicitly start the executable even if original executable was created in "delay-start" mode.
11011106 er . DcpResource . Spec . Start = true ;
@@ -1125,32 +1130,12 @@ public async Task StartResourceAsync(IResourceReference resourceReference, Cance
11251130 }
11261131 }
11271132
1128- private async Task < bool > TryStartCreatedDelayedStartResourceAsync ( IResourceReference resourceReference , string resourceType , CancellationToken cancellationToken )
1133+ private async Task EnsureResourceDeletedAsync < T > ( IResourceReference resource , CancellationToken cancellationToken ) where T : CustomResource , IKubernetesStaticMetadata
11291134 {
1130- switch ( resourceReference )
1131- {
1132- case RenderedModelResource < Container > { DcpResource . Spec . Start : false } cr
1133- when ! DcpModelUtilities . ShouldDeferCreateForExplicitStart ( cr . ModelResource , cr . DcpResource . Spec . Start ) :
1134- await PublishConnectionStringAvailableEventAsync ( cr . ModelResource , cancellationToken ) . ConfigureAwait ( false ) ;
1135- await _executorEvents . PublishAsync ( new OnResourceStartingContext ( cancellationToken , resourceType , cr . ModelResource , cr . DcpResourceName ) ) . ConfigureAwait ( false ) ;
1136- await PatchDcpObjectAsync ( cr . DcpResource , static c => c . Spec . Start = true , cancellationToken ) . ConfigureAwait ( false ) ;
1137- return true ;
1138-
1139- case RenderedModelResource < Executable > { DcpResource . Spec . Start : false } er
1140- when ! DcpModelUtilities . ShouldDeferCreateForExplicitStart ( er . ModelResource , er . DcpResource . Spec . Start ) :
1141- await PublishConnectionStringAvailableEventAsync ( er . ModelResource , cancellationToken ) . ConfigureAwait ( false ) ;
1142- await _executorEvents . PublishAsync ( new OnResourceStartingContext ( cancellationToken , resourceType , er . ModelResource , er . DcpResourceName ) ) . ConfigureAwait ( false ) ;
1143- await PatchDcpObjectAsync ( er . DcpResource , static e => e . Spec . Start = true , cancellationToken ) . ConfigureAwait ( false ) ;
1144- return true ;
1145-
1146- default :
1147- return false ;
1148- }
1149- }
1135+ _logger . LogDebug ( "Ensuring '{ResourceName}' is deleted." , resource . DcpResourceName ) ;
11501136
1151- private async Task EnsureResourceDeletedAsync < T > ( string resourceName , CancellationToken cancellationToken ) where T : CustomResource , IKubernetesStaticMetadata
1152- {
1153- _logger . LogDebug ( "Ensuring '{ResourceName}' is deleted." , resourceName ) ;
1137+ // Reset cached callback results so they are re-evaluated on restart.
1138+ ForgetCachedCallbackResults ( resource . ModelResource ) ;
11541139
11551140 var result = await DeleteResourceRetryPipeline . ExecuteAsync ( async ( resourceName , attemptCancellationToken ) =>
11561141 {
@@ -1194,11 +1179,11 @@ private async Task EnsureResourceDeletedAsync<T>(string resourceName, Cancellati
11941179 // Success.
11951180 return true ;
11961181 }
1197- } , resourceName , cancellationToken ) . ConfigureAwait ( false ) ;
1182+ } , resource . DcpResourceName , cancellationToken ) . ConfigureAwait ( false ) ;
11981183
11991184 if ( ! result )
12001185 {
1201- throw new DistributedApplicationException ( $ "Failed to delete '{ resourceName } ' successfully before restart.") ;
1186+ throw new DistributedApplicationException ( $ "Failed to delete '{ resource . DcpResourceName } ' successfully before restart.") ;
12021187 }
12031188 }
12041189
0 commit comments