22// The .NET Foundation licenses this file to you under the Apache 2.0 License.
33// See the LICENSE file in the project root for more information.
44
5+ using System . Collections . ObjectModel ;
56using System . Text ;
67using Microsoft . Extensions . Logging ;
78using Microsoft . Extensions . Options ;
@@ -69,6 +70,9 @@ internal ApplicationInfoCollection Applications
6970 /// </summary>
7071 public event EventHandler < ApplicationsFetchedEventArgs > ? ApplicationsFetched ;
7172
73+ /// <inheritdoc />
74+ public event EventHandler < DiscoveryInstancesFetchedEventArgs > ? InstancesFetched ;
75+
7276 public EurekaDiscoveryClient ( EurekaApplicationInfoManager appInfoManager , EurekaClient eurekaClient ,
7377 IOptionsMonitor < EurekaClientOptions > clientOptionsMonitor , HealthCheckHandlerProvider healthCheckHandlerProvider , TimeProvider timeProvider ,
7478 ILogger < EurekaDiscoveryClient > logger )
@@ -326,7 +330,8 @@ internal async Task FetchRegistryAsync(bool doFullUpdate, CancellationToken canc
326330
327331 await _registryFetchAsyncLock . WaitAsync ( cancellationToken ) ;
328332
329- ApplicationsFetchedEventArgs eventArgs ;
333+ ApplicationsFetchedEventArgs ? applicationsEventArgs = null ;
334+ DiscoveryInstancesFetchedEventArgs ? instancesEventArgs = null ;
330335
331336 try
332337 {
@@ -344,33 +349,75 @@ internal async Task FetchRegistryAsync(bool doFullUpdate, CancellationToken canc
344349
345350 UpdateLastRemoteInstanceStatusFromCache ( ) ;
346351
347- eventArgs = new ApplicationsFetchedEventArgs ( _remoteApps ) ;
352+ if ( ApplicationsFetched != null )
353+ {
354+ applicationsEventArgs = new ApplicationsFetchedEventArgs ( _remoteApps ) ;
355+ }
356+
357+ if ( InstancesFetched != null )
358+ {
359+ ReadOnlyDictionary < string , IReadOnlyList < IServiceInstance > > instancesByServiceId = ToServiceInstanceMap ( _remoteApps ) ;
360+ instancesEventArgs = new DiscoveryInstancesFetchedEventArgs ( instancesByServiceId ) ;
361+ }
348362 }
349363 finally
350364 {
351365 _registryFetchAsyncLock . Release ( ) ;
352366 }
353367
354- OnApplicationsFetched ( eventArgs ) ;
368+ if ( applicationsEventArgs != null || instancesEventArgs != null )
369+ {
370+ RaiseFetchEvents ( applicationsEventArgs , instancesEventArgs ) ;
371+ }
355372 }
356373
357- private void OnApplicationsFetched ( ApplicationsFetchedEventArgs ? args )
374+ private static ReadOnlyDictionary < string , IReadOnlyList < IServiceInstance > > ToServiceInstanceMap ( ApplicationInfoCollection apps )
358375 {
359- if ( args != null )
376+ // @formatter:wrap_chained_method_calls chop_always
377+ // @formatter:wrap_before_first_method_call true
378+
379+ return apps
380+ . SelectMany ( app => app . Instances )
381+ . GroupBy ( instance => instance . AppName , StringComparer . OrdinalIgnoreCase )
382+ . ToDictionary ( grouping => grouping . Key , grouping => ( IReadOnlyList < IServiceInstance > ) grouping
383+ . Select ( instance => instance . ToServiceInstance ( ) )
384+ . ToList ( )
385+ . AsReadOnly ( ) )
386+ . AsReadOnly ( ) ;
387+
388+ // @formatter:wrap_before_first_method_call restore
389+ // @formatter:wrap_chained_method_calls restore
390+ }
391+
392+ private void RaiseFetchEvents ( ApplicationsFetchedEventArgs ? applicationsEventArgs , DiscoveryInstancesFetchedEventArgs ? instancesEventArgs )
393+ {
394+ // Execute on separate thread, so we won't block the periodic refresh in case the handler logic is expensive.
395+ ThreadPool . QueueUserWorkItem ( _ =>
360396 {
361- // Execute on separate thread, so we won't block the periodic refresh in case the handler logic is expensive.
362- ThreadPool . QueueUserWorkItem ( _ =>
397+ try
363398 {
364- try
399+ if ( applicationsEventArgs != null )
365400 {
366- ApplicationsFetched ? . Invoke ( this , args ) ;
401+ ApplicationsFetched ? . Invoke ( this , applicationsEventArgs ) ;
367402 }
368- catch ( Exception exception )
403+ }
404+ catch ( Exception exception )
405+ {
406+ LogFailedToHandleEvent ( exception , nameof ( ApplicationsFetched ) ) ;
407+ }
408+
409+ try
410+ {
411+ if ( instancesEventArgs != null )
369412 {
370- LogFailedToHandleEvent ( exception , nameof ( ApplicationsFetched ) ) ;
413+ InstancesFetched ? . Invoke ( this , instancesEventArgs ) ;
371414 }
372- } ) ;
373- }
415+ }
416+ catch ( Exception exception )
417+ {
418+ LogFailedToHandleEvent ( exception , nameof ( InstancesFetched ) ) ;
419+ }
420+ } ) ;
374421 }
375422
376423 internal async Task < ApplicationInfoCollection > FetchFullRegistryAsync ( CancellationToken cancellationToken )
0 commit comments