@@ -20,10 +20,7 @@ public sealed class ShellScope : IServiceScope, IAsyncDisposable
2020 private List < Func < ShellScope , Task > > _deferredTasks ;
2121 private List < Func < ShellScope , Exception , Task > > _exceptionHandlers ;
2222
23- private bool _serviceScopeOnly ;
24- private bool _shellTerminated ;
25- private bool _terminated ;
26- private bool _disposed ;
23+ private ShellScopeStates _state ;
2724
2825 /// <summary>
2926 /// Initializes a <see cref="ShellScope"/> from a given parent <see cref="Builders.ShellContext"/>.
@@ -255,7 +252,7 @@ public void StartAsyncFlow()
255252 /// </summary>
256253 public Task UsingServiceScopeAsync ( Func < ShellScope , Task > execute )
257254 {
258- _serviceScopeOnly = true ;
255+ _state |= ShellScopeStates . ServiceScopeOnly ;
259256 return UsingAsync ( execute ) ;
260257 }
261258
@@ -325,7 +322,7 @@ internal async Task ActivateShellInternalAsync()
325322 return ;
326323 }
327324
328- if ( _serviceScopeOnly )
325+ if ( _state . HasFlag ( ShellScopeStates . ServiceScopeOnly ) )
329326 {
330327 return ;
331328 }
@@ -376,6 +373,8 @@ internal async Task ActivateShellInternalAsync()
376373 /// If true, the delegate is added to the end of the invocation list; otherwise, it is added to the beginning.</param>
377374 internal void BeforeDispose ( Func < ShellScope , Task > callback , bool last )
378375 {
376+ ThrowIfTerminating ( ) ;
377+
379378 var list = _beforeDispose ??= [ ] ;
380379
381380 if ( last )
@@ -391,17 +390,32 @@ internal void BeforeDispose(Func<ShellScope, Task> callback, bool last)
391390 /// <summary>
392391 /// Adds a Signal (if not already present) to be sent just after 'BeforeDisposeAsync()'.
393392 /// </summary>
394- internal void DeferredSignal ( string key ) => ( _deferredSignals ??= [ ] ) . Add ( key ) ;
393+ internal void DeferredSignal ( string key )
394+ {
395+ ThrowIfTerminating ( ) ;
396+
397+ ( _deferredSignals ??= [ ] ) . Add ( key ) ;
398+ }
395399
396400 /// <summary>
397401 /// Adds a Task to be executed in a new scope after 'BeforeDisposeAsync()'.
398402 /// </summary>
399- internal void DeferredTask ( Func < ShellScope , Task > task ) => ( _deferredTasks ??= [ ] ) . Add ( task ) ;
403+ internal void DeferredTask ( Func < ShellScope , Task > task )
404+ {
405+ ThrowIfTerminating ( ) ;
406+
407+ ( _deferredTasks ??= [ ] ) . Add ( task ) ;
408+ }
400409
401410 /// <summary>
402411 /// Adds an handler to be invoked if an exception is thrown while executing in this shell scope.
403412 /// </summary>
404- internal void ExceptionHandler ( Func < ShellScope , Exception , Task > callback ) => ( _exceptionHandlers ??= [ ] ) . Add ( callback ) ;
413+ internal void ExceptionHandler ( Func < ShellScope , Exception , Task > callback )
414+ {
415+ ThrowIfTerminating ( ) ;
416+
417+ ( _exceptionHandlers ??= [ ] ) . Add ( callback ) ;
418+ }
405419
406420 /// <summary>
407421 /// Registers a delegate to be invoked before the current shell scope will be disposed.
@@ -453,7 +467,7 @@ internal async Task BeforeDisposeAsync()
453467 }
454468 }
455469
456- if ( _serviceScopeOnly )
470+ if ( _state . HasFlag ( ShellScopeStates . ServiceScopeOnly ) )
457471 {
458472 return ;
459473 }
@@ -516,12 +530,14 @@ await scope.UsingAsync(async scope =>
516530 /// </summary>
517531 internal async Task TerminateShellInternalAsync ( )
518532 {
519- if ( _serviceScopeOnly )
533+ _state |= ShellScopeStates . IsTerminating ;
534+
535+ if ( _state . HasFlag ( ShellScopeStates . ServiceScopeOnly ) )
520536 {
521537 return ;
522538 }
523539
524- _terminated = true ;
540+ _state |= ShellScopeStates . Terminated ;
525541
526542 // If the shell context is released and in its last shell scope, according to the ref counter value,
527543 // the terminate event handlers are called, and the shell will be disposed at the end of this scope.
@@ -552,7 +568,7 @@ internal async Task TerminateShellInternalAsync()
552568 return ;
553569 }
554570
555- _shellTerminated = true ;
571+ _state |= ShellScopeStates . ShellTerminated ;
556572
557573 var tenantEvents = _serviceScope . ServiceProvider . GetServices < IModularTenantEvents > ( ) ;
558574 foreach ( var tenantEvent in tenantEvents )
@@ -569,16 +585,16 @@ internal async Task TerminateShellInternalAsync()
569585
570586 public void Dispose ( )
571587 {
572- if ( _disposed )
588+ if ( _state . HasFlag ( ShellScopeStates . IsDisposed ) )
573589 {
574590 return ;
575591 }
576592
577- _disposed = true ;
593+ _state |= ShellScopeStates . IsDisposed ;
578594
579595 _serviceScope . Dispose ( ) ;
580596
581- if ( _shellTerminated )
597+ if ( _state . HasFlag ( ShellScopeStates . ShellTerminated ) )
582598 {
583599 ShellContext . Dispose ( ) ;
584600 }
@@ -588,16 +604,16 @@ public void Dispose()
588604
589605 public async ValueTask DisposeAsync ( )
590606 {
591- if ( _disposed )
607+ if ( _state . HasFlag ( ShellScopeStates . IsDisposed ) )
592608 {
593609 return ;
594610 }
595611
596- _disposed = true ;
612+ _state |= ShellScopeStates . IsDisposed ;
597613
598614 await _serviceScope . DisposeAsync ( ) ;
599615
600- if ( _shellTerminated )
616+ if ( _state . HasFlag ( ShellScopeStates . ShellTerminated ) )
601617 {
602618 await ShellContext . DisposeAsync ( ) ;
603619 }
@@ -607,7 +623,7 @@ public async ValueTask DisposeAsync()
607623
608624 private void Terminate ( )
609625 {
610- if ( ! _terminated )
626+ if ( ! _state . HasFlag ( ShellScopeStates . Terminated ) )
611627 {
612628 // Keep the counter clean if not yet decremented.
613629 Interlocked . Decrement ( ref ShellContext . _refCount ) ;
@@ -621,8 +637,27 @@ private void Terminate()
621637 }
622638 }
623639
640+ private void ThrowIfTerminating ( )
641+ {
642+ if ( _state . HasFlag ( ShellScopeStates . IsTerminating ) )
643+ {
644+ throw new InvalidOperationException (
645+ $ "Cannot perform this operation because the shell scope for tenant '{ ShellContext . Settings . Name } ' is already terminating.") ;
646+ }
647+ }
648+
624649 private sealed class ShellScopeHolder
625650 {
626651 public ShellScope Scope ;
627652 }
653+
654+ [ Flags ]
655+ private enum ShellScopeStates : byte
656+ {
657+ ServiceScopeOnly = 1 ,
658+ ShellTerminated = 2 ,
659+ IsTerminating = 4 ,
660+ Terminated = 8 ,
661+ IsDisposed = 16 ,
662+ }
628663}
0 commit comments