@@ -52,8 +52,7 @@ public ApplicationOrchestrator(DistributedApplicationModel model,
52
52
dcpExecutorEvents . Subscribe < OnResourceStartingContext > ( OnResourceStarting ) ;
53
53
dcpExecutorEvents . Subscribe < OnResourceFailedToStartContext > ( OnResourceFailedToStart ) ;
54
54
55
- _eventing . Subscribe < ResourceEndpointsAllocatedEvent > ( ProcessResourcesWithoutLifetime ) ;
56
- _eventing . Subscribe < ResourceEndpointsAllocatedEvent > ( PublishInitialResourceUrls ) ;
55
+ _eventing . Subscribe < ResourceEndpointsAllocatedEvent > ( OnResourceEndpointsAllocated ) ;
57
56
_eventing . Subscribe < ConnectionStringAvailableEvent > ( PublishConnectionStringValue ) ;
58
57
// Implement WaitFor functionality using BeforeResourceStartedEvent.
59
58
_eventing . Subscribe < BeforeResourceStartedEvent > ( WaitForInBeforeResourceStartedEvent ) ;
@@ -118,32 +117,32 @@ private async Task OnEndpointsAllocated(OnEndpointsAllocatedContext context)
118
117
{
119
118
await lifecycleHook . AfterEndpointsAllocatedAsync ( _model , context . CancellationToken ) . ConfigureAwait ( false ) ;
120
119
}
121
-
122
- // Fire the endpoints allocated event for all resources.
123
- foreach ( var resource in _model . Resources )
124
- {
125
- await _eventing . PublishAsync ( new ResourceEndpointsAllocatedEvent ( resource , _serviceProvider ) , EventDispatchBehavior . NonBlockingConcurrent , context . CancellationToken ) . ConfigureAwait ( false ) ;
126
- }
127
120
}
128
121
129
- private async Task PublishInitialResourceUrls ( ResourceEndpointsAllocatedEvent @event , CancellationToken cancellationToken )
122
+ private async Task PublishResourceEndpointUrls ( IResource resource , CancellationToken cancellationToken )
130
123
{
131
- var resource = @event . Resource ;
132
-
133
124
// Process URLs for the resource.
134
- await ProcessUrls ( resource , cancellationToken ) . ConfigureAwait ( false ) ;
125
+ await ProcessResourceUrlCallbacks ( resource , cancellationToken ) . ConfigureAwait ( false ) ;
126
+
127
+ // Publish update with URLs.
128
+ var urls = GetResourceUrls ( resource ) ;
129
+ await _notificationService . PublishUpdateAsync ( resource , s => s with { Urls = [ .. urls ] } ) . ConfigureAwait ( false ) ;
130
+ }
135
131
132
+ private static IEnumerable < UrlSnapshot > GetResourceUrls ( IResource resource )
133
+ {
136
134
IEnumerable < UrlSnapshot > urls = [ ] ;
137
135
if ( resource . TryGetUrls ( out var resourceUrls ) )
138
136
{
139
137
urls = resourceUrls . Select ( url => new UrlSnapshot ( Name : url . Endpoint ? . EndpointName , Url : url . Url , IsInternal : url . DisplayLocation == UrlDisplayLocation . DetailsOnly )
140
138
{
141
- IsInactive = true ,
139
+ // Endpoint URLs are inactive (hidden in the dashboard) when published here. It is assumed they will get activated later when the endpoint is considered active
140
+ // by whatever allocated the endpoint in the first place, e.g. for resources controlled by DCP, when DCP detects the endpoint is listening.
141
+ IsInactive = url . Endpoint is not null ,
142
142
DisplayProperties = new ( url . DisplayText ?? "" , url . DisplayOrder ?? 0 )
143
143
} ) ;
144
144
}
145
-
146
- await _notificationService . PublishUpdateAsync ( resource , s => s with { Urls = [ .. urls ] } ) . ConfigureAwait ( false ) ;
145
+ return urls ;
147
146
}
148
147
149
148
private async Task OnResourceStarting ( OnResourceStartingContext context )
@@ -196,16 +195,17 @@ private async Task OnResourcesPrepared(OnResourcesPreparedContext context)
196
195
await PublishResourcesInitialStateAsync ( context . CancellationToken ) . ConfigureAwait ( false ) ;
197
196
}
198
197
199
- private async Task ProcessUrls ( IResource resource , CancellationToken cancellationToken )
198
+ private async Task ProcessResourceUrlCallbacks ( IResource resource , CancellationToken cancellationToken )
200
199
{
201
- // Project endpoints to URLS
202
200
var urls = new List < ResourceUrlAnnotation > ( ) ;
203
201
202
+ // Project endpoints to URLs
204
203
if ( resource . TryGetEndpoints ( out var endpoints ) && resource is IResourceWithEndpoints resourceWithEndpoints )
205
204
{
206
205
foreach ( var endpoint in endpoints )
207
206
{
208
207
// Create a URL for each endpoint
208
+ Debug . Assert ( endpoint . AllocatedEndpoint is not null , "Endpoint should be allocated at this point as we're calling this from ResourceEndpointsAllocatedEvent handler." ) ;
209
209
if ( endpoint . AllocatedEndpoint is { } allocatedEndpoint )
210
210
{
211
211
var url = new ResourceUrlAnnotation { Url = allocatedEndpoint . UriString , Endpoint = new EndpointReference ( resourceWithEndpoints , endpoint ) } ;
@@ -214,6 +214,12 @@ private async Task ProcessUrls(IResource resource, CancellationToken cancellatio
214
214
}
215
215
}
216
216
217
+ if ( resource . TryGetUrls ( out var existingUrls ) )
218
+ {
219
+ // Static URLs added to the resource via WithUrl(string name, string url), i.e. not callback-based
220
+ urls . AddRange ( existingUrls ) ;
221
+ }
222
+
217
223
// Run the URL callbacks
218
224
if ( resource . TryGetAnnotationsOfType < ResourceUrlsCallbackAnnotation > ( out var callbacks ) )
219
225
{
@@ -228,7 +234,7 @@ private async Task ProcessUrls(IResource resource, CancellationToken cancellatio
228
234
}
229
235
230
236
// Clear existing URLs
231
- if ( resource . TryGetUrls ( out var existingUrls ) )
237
+ if ( existingUrls is not null )
232
238
{
233
239
var existing = existingUrls . ToArray ( ) ;
234
240
for ( var i = existing . Length - 1 ; i >= 0 ; i -- )
@@ -257,34 +263,36 @@ private async Task ProcessUrls(IResource resource, CancellationToken cancellatio
257
263
}
258
264
}
259
265
260
- private async Task ProcessResourcesWithoutLifetime ( ResourceEndpointsAllocatedEvent @event , CancellationToken cancellationToken )
266
+ private async Task OnResourceEndpointsAllocated ( ResourceEndpointsAllocatedEvent @event , CancellationToken cancellationToken )
261
267
{
262
- if ( @event . Resource is not IResourceWithoutLifetime resource )
263
- {
264
- return ;
265
- }
268
+ await ProcessResourceWithoutLifetime ( @event . Resource , cancellationToken ) . ConfigureAwait ( false ) ;
269
+ await PublishResourceEndpointUrls ( @event . Resource , cancellationToken ) . ConfigureAwait ( false ) ;
270
+ }
266
271
267
- if ( resource is not IValueProvider valueProvider )
272
+ private async Task ProcessResourceWithoutLifetime ( IResource resource , CancellationToken cancellationToken )
273
+ {
274
+ if ( resource is not IResourceWithoutLifetime resourceWithoutLifetime
275
+ || resourceWithoutLifetime is not IValueProvider valueProvider )
268
276
{
269
277
return ;
270
278
}
271
279
272
280
try
273
281
{
274
- var value = await valueProvider . GetValueAsync ( default ) . ConfigureAwait ( false ) ;
282
+ var value = await valueProvider . GetValueAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
275
283
276
- await _notificationService . PublishUpdateAsync ( resource , s =>
284
+ await _notificationService . PublishUpdateAsync ( resourceWithoutLifetime , s =>
277
285
{
278
286
return s with
279
287
{
280
- Properties = s . Properties . SetResourceProperty ( "Value" , value ?? "" , resource is ParameterResource p && p . Secret )
288
+ Properties = s . Properties . SetResourceProperty ( "Value" , value ?? "" , resourceWithoutLifetime is ParameterResource p && p . Secret )
281
289
} ;
282
290
} )
283
291
. ConfigureAwait ( false ) ;
284
292
}
285
293
catch ( Exception ex )
286
294
{
287
- await _notificationService . PublishUpdateAsync ( resource , s =>
295
+ await _notificationService . PublishUpdateAsync ( resourceWithoutLifetime , s =>
288
296
{
289
297
return s with
290
298
{
@@ -294,7 +302,7 @@ await _notificationService.PublishUpdateAsync(resource, s =>
294
302
} )
295
303
. ConfigureAwait ( false ) ;
296
304
297
- _loggerService . GetLogger ( resource . Name ) . LogError ( "{Message}" , ex . Message ) ;
305
+ _loggerService . GetLogger ( resourceWithoutLifetime . Name ) . LogError ( "{Message}" , ex . Message ) ;
298
306
}
299
307
}
300
308
@@ -407,12 +415,14 @@ private async Task PublishResourcesInitialStateAsync(CancellationToken cancellat
407
415
var parent = resource is IResourceWithParent hasParent
408
416
? hasParent . Parent
409
417
: resource . Annotations . OfType < ResourceRelationshipAnnotation > ( ) . LastOrDefault ( r => r . Type == KnownRelationshipTypes . Parent ) ? . Resource ;
418
+ var urls = GetResourceUrls ( resource ) ;
410
419
411
420
await _notificationService . PublishUpdateAsync ( resource , s =>
412
421
{
413
422
return s with
414
423
{
415
424
Relationships = relationships ,
425
+ Urls = [ .. urls ] ,
416
426
Properties = parent is null ? s . Properties : s . Properties . SetResourceProperty ( KnownProperties . Resource . ParentName , parent . GetResolvedResourceNames ( ) [ 0 ] ) ,
417
427
HealthReports = GetInitialHealthReports ( resource )
418
428
} ;
0 commit comments