@@ -332,6 +332,7 @@ public actor ServiceGroup: Sendable {
332
332
group: & group,
333
333
gracefulShutdownManagers: gracefulShutdownManagers
334
334
)
335
+ return . success( ( ) )
335
336
} catch {
336
337
return . failure( error)
337
338
}
@@ -425,6 +426,7 @@ public actor ServiceGroup: Sendable {
425
426
group: & group,
426
427
gracefulShutdownManagers: gracefulShutdownManagers
427
428
)
429
+ return . success( ( ) )
428
430
} catch {
429
431
return . failure( error)
430
432
}
@@ -451,6 +453,7 @@ public actor ServiceGroup: Sendable {
451
453
group: & group,
452
454
gracefulShutdownManagers: gracefulShutdownManagers
453
455
)
456
+ return . success( ( ) )
454
457
} catch {
455
458
return . failure( error)
456
459
}
@@ -511,7 +514,7 @@ public actor ServiceGroup: Sendable {
511
514
// We have to shutdown the services in reverse. To do this
512
515
// we are going to signal each child task the graceful shutdown and then wait for
513
516
// its exit.
514
- for (gracefulShutdownIndex, gracefulShutdownManager) in gracefulShutdownManagers. lazy. enumerated ( ) . reversed ( ) {
517
+ gracefulShutdownLoop: for ( gracefulShutdownIndex, gracefulShutdownManager) in gracefulShutdownManagers. lazy. enumerated ( ) . reversed ( ) {
515
518
guard let service = services [ gracefulShutdownIndex] else {
516
519
self . logger. debug (
517
520
" Service already finished. Skipping shutdown "
@@ -527,112 +530,114 @@ public actor ServiceGroup: Sendable {
527
530
528
531
gracefulShutdownManager. shutdownGracefully ( )
529
532
530
- let result = try await group. next ( )
533
+ while let result = try await group. next ( ) {
534
+ switch result {
535
+ case . serviceFinished( let service, let index) :
536
+ if group. isCancelled {
537
+ // The group is cancelled and we expect all services to finish
538
+ continue gracefulShutdownLoop
539
+ }
531
540
532
- switch result {
533
- case . serviceFinished( let service, let index) :
534
- if group. isCancelled {
535
- // The group is cancelled and we expect all services to finish
536
- continue
537
- }
541
+ if index == gracefulShutdownIndex {
542
+ // The service that we signalled graceful shutdown did exit/
543
+ // We can continue to the next one.
544
+ self . logger. debug (
545
+ " Service finished " ,
546
+ metadata: [
547
+ self . loggingConfiguration. keys. serviceKey: " \( service. service) " ,
548
+ ]
549
+ )
550
+ continue gracefulShutdownLoop
551
+ } else {
552
+ // Another service exited unexpectedly
553
+ self . logger. debug (
554
+ " Service finished unexpectedly during graceful shutdown. Cancelling all other services now " ,
555
+ metadata: [
556
+ self . loggingConfiguration. keys. serviceKey: " \( service. service) " ,
557
+ ]
558
+ )
538
559
539
- if index == gracefulShutdownIndex {
540
- // The service that we signalled graceful shutdown did exit/
541
- // We can continue to the next one.
542
- self . logger. debug (
543
- " Service finished " ,
544
- metadata: [
545
- self . loggingConfiguration. keys. serviceKey: " \( service. service) " ,
546
- ]
547
- )
548
- continue
549
- } else {
550
- // Another service exited unexpectedly
551
- self . logger. debug (
552
- " Service finished unexpectedly during graceful shutdown. Cancelling all other services now " ,
553
- metadata: [
554
- self . loggingConfiguration. keys. serviceKey: " \( service. service) " ,
555
- ]
556
- )
560
+ self . cancelGroupAndSpawnTimeoutIfNeeded ( group: & group, cancellationTimeoutTask: & cancellationTimeoutTask)
561
+ throw ServiceGroupError . serviceFinishedUnexpectedly ( )
562
+ }
557
563
558
- self . cancelGroupAndSpawnTimeoutIfNeeded ( group: & group, cancellationTimeoutTask: & cancellationTimeoutTask)
559
- throw ServiceGroupError . serviceFinishedUnexpectedly ( )
560
- }
564
+ case . serviceThrew( let service, _, let serviceError) :
565
+ switch service. failureTerminationBehavior. behavior {
566
+ case . cancelGroup:
567
+ self . logger. debug (
568
+ " Service threw error during graceful shutdown. Cancelling group. " ,
569
+ metadata: [
570
+ self . loggingConfiguration. keys. serviceKey: " \( service. service) " ,
571
+ self . loggingConfiguration. keys. errorKey: " \( serviceError) " ,
572
+ ]
573
+ )
574
+ group. cancelAll ( )
575
+ throw serviceError
561
576
562
- case . serviceThrew( let service, _, let serviceError) :
563
- switch service. failureTerminationBehavior. behavior {
564
- case . cancelGroup:
565
- self . logger. debug (
566
- " Service threw error during graceful shutdown. Cancelling group. " ,
567
- metadata: [
568
- self . loggingConfiguration. keys. serviceKey: " \( service. service) " ,
569
- self . loggingConfiguration. keys. errorKey: " \( serviceError) " ,
570
- ]
571
- )
572
- group. cancelAll ( )
573
- throw serviceError
577
+ case . gracefullyShutdownGroup:
578
+ self . logger. debug (
579
+ " Service threw error during graceful shutdown. " ,
580
+ metadata: [
581
+ self . loggingConfiguration. keys. serviceKey: " \( service. service) " ,
582
+ self . loggingConfiguration. keys. errorKey: " \( serviceError) " ,
583
+ ]
584
+ )
574
585
575
- case . gracefullyShutdownGroup:
576
- self . logger. debug (
577
- " Service threw error during graceful shutdown. " ,
578
- metadata: [
579
- self . loggingConfiguration. keys. serviceKey: " \( service. service) " ,
580
- self . loggingConfiguration. keys. errorKey: " \( serviceError) " ,
581
- ]
582
- )
586
+ if error == nil {
587
+ error = serviceError
588
+ }
583
589
584
- if error == nil {
585
- error = serviceError
590
+ // We can continue shutting down the next service now
591
+ continue gracefulShutdownLoop
592
+
593
+ case . ignore:
594
+ self . logger. debug (
595
+ " Service threw error during graceful shutdown. " ,
596
+ metadata: [
597
+ self . loggingConfiguration. keys. serviceKey: " \( service. service) " ,
598
+ self . loggingConfiguration. keys. errorKey: " \( serviceError) " ,
599
+ ]
600
+ )
601
+
602
+ // We can continue shutting down the next service now
603
+ continue gracefulShutdownLoop
586
604
}
587
605
588
- case . ignore:
589
- self . logger. debug (
590
- " Service threw error during graceful shutdown. " ,
591
- metadata: [
592
- self . loggingConfiguration. keys. serviceKey: " \( service. service) " ,
593
- self . loggingConfiguration. keys. errorKey: " \( serviceError) " ,
594
- ]
595
- )
606
+ case . signalCaught( let signal) :
607
+ if self . cancellationSignals. contains ( signal) {
608
+ // We got signalled cancellation after graceful shutdown
609
+ self . logger. debug (
610
+ " Signal caught. Cancelling the group. " ,
611
+ metadata: [
612
+ self . loggingConfiguration. keys. signalKey: " \( signal) " ,
613
+ ]
614
+ )
596
615
597
- continue
598
- }
616
+ self . cancelGroupAndSpawnTimeoutIfNeeded ( group : & group , cancellationTimeoutTask : & cancellationTimeoutTask )
617
+ }
599
618
600
- case . signalCaught ( let signal ) :
601
- if self . cancellationSignals . contains ( signal ) {
602
- // We got signalled cancellation after graceful shutdown
619
+ case . gracefulShutdownTimedOut :
620
+ // Gracefully shutting down took longer than the user configured
621
+ // so we have to escalate it now.
603
622
self . logger. debug (
604
- " Signal caught . Cancelling the group." ,
623
+ " Graceful shutdown took longer than allowed by the configuration . Cancelling the group now ." ,
605
624
metadata: [
606
- self . loggingConfiguration. keys. signalKey : " \( signal ) " ,
625
+ self . loggingConfiguration. keys. serviceKey : " \( service . service ) " ,
607
626
]
608
627
)
609
-
610
628
self . cancelGroupAndSpawnTimeoutIfNeeded ( group: & group, cancellationTimeoutTask: & cancellationTimeoutTask)
611
- }
612
629
613
- case . gracefulShutdownTimedOut:
614
- // Gracefully shutting down took longer than the user configured
615
- // so we have to escalate it now.
616
- self . logger. debug (
617
- " Graceful shutdown took longer than allowed by the configuration. Cancelling the group now. " ,
618
- metadata: [
619
- self . loggingConfiguration. keys. serviceKey: " \( service. service) " ,
620
- ]
621
- )
622
- self . cancelGroupAndSpawnTimeoutIfNeeded ( group: & group, cancellationTimeoutTask: & cancellationTimeoutTask)
623
-
624
- case . cancellationCaught:
625
- // We caught cancellation in our child task so we have to spawn
626
- // our cancellation timeout task if needed
627
- self . logger. debug ( " Caught cancellation. " )
628
- self . cancelGroupAndSpawnTimeoutIfNeeded ( group: & group, cancellationTimeoutTask: & cancellationTimeoutTask)
629
-
630
- case . signalSequenceFinished, . gracefulShutdownCaught, . gracefulShutdownFinished:
631
- // We just have to tolerate this since signals and parent graceful shutdowns downs can race.
632
- continue
630
+ case . cancellationCaught:
631
+ // We caught cancellation in our child task so we have to spawn
632
+ // our cancellation timeout task if needed
633
+ self . logger. debug ( " Caught cancellation. " )
634
+ self . cancelGroupAndSpawnTimeoutIfNeeded ( group: & group, cancellationTimeoutTask: & cancellationTimeoutTask)
633
635
634
- case nil :
635
- fatalError ( " Invalid result from group.next(). " )
636
+ case . signalSequenceFinished, . gracefulShutdownCaught, . gracefulShutdownFinished:
637
+ // We just have to tolerate this since signals and parent graceful shutdowns downs can race.
638
+ // We are going to continue the
639
+ break
640
+ }
636
641
}
637
642
}
638
643
0 commit comments