public async Task BeforeDisposeAsync() { foreach (var callback in _beforeDispose) { await callback(this); } if (_deferredSignals.Any()) { var signal = ShellContext.ServiceProvider.GetRequiredService <ISignal>(); foreach (var key in _deferredSignals) { await signal.SignalTokenAsync(key); } } if (_deferredTasks.Any()) { var shellHost = ShellContext.ServiceProvider.GetRequiredService <IShellHost>(); foreach (var task in _deferredTasks) { ShellScope scope; // Create a new scope (maybe based on a new shell) for each task. try { // May fail if a shell was released before being disabled. scope = await shellHost.GetScopeAsync(ShellContext.Settings); } catch { // Fallback to a scope based on the current shell that is not yet disposed. scope = new ShellScope(ShellContext); } using (scope) { scope.StartAsyncFlow(); var logger = scope.ServiceProvider.GetService <ILogger <ShellScope> >(); try { await task(scope); } catch (Exception e) { logger?.LogError(e, "Error while processing deferred task '{TaskName}' on tenant '{TenantName}'.", task.GetType().FullName, ShellContext.Settings.Name); } await scope.BeforeDisposeAsync(); await scope.DisposeAsync(); } } } }
/// <summary> /// Adds an handler task to be invoked if an exception is thrown while executing in this shell scope. /// </summary> public static ShellScope AddExceptionHandler(this ShellScope scope, Func <ShellScope, Exception, Task> handler) { scope?.ExceptionHandler(handler); return(scope); }
/// <summary> /// Adds a Task to be executed in a new scope once this shell scope has been disposed. /// </summary> public static ShellScope AddDeferredTask(this ShellScope scope, Func <ShellScope, Task> task) { scope?.DeferredTask(task); return(scope); }
/// <summary> /// Adds a Signal (if not already present) to be sent just before this shell scope will be disposed. /// </summary> public static ShellScope AddDeferredSignal(this ShellScope scope, string key) { scope?.DeferredSignal(key); return(scope); }
/// <summary> /// Registers a delegate task to be invoked before this shell scope will be disposed. /// </summary> public static ShellScope RegisterBeforeDispose(this ShellScope scope, Func <ShellScope, Task> callback) { scope?.BeforeDispose(callback); return(scope); }
internal async Task BeforeDisposeAsync() { foreach (var callback in _beforeDispose) { await callback(this); } if (_serviceScopeOnly) { return; } if (_deferredSignals.Any()) { var signal = ShellContext.ServiceProvider.GetRequiredService <ISignal>(); foreach (var key in _deferredSignals) { await signal.SignalTokenAsync(key); } } if (_deferredTasks.Any()) { var shellHost = ShellContext.ServiceProvider.GetRequiredService <IShellHost>(); foreach (var task in _deferredTasks) { // Create a new scope (maybe based on a new shell) for each task. ShellScope scope; try { // May fail if a shell was released before being disabled. scope = await shellHost.GetScopeAsync(ShellContext.Settings); } catch { // Fallback to a scope based on the current shell that is not yet disposed. scope = new ShellScope(ShellContext); } // Use 'UsingAsync' in place of 'UsingServiceScopeAsync()' to allow a deferred task to // trigger another one, but still prevent the shell to be activated in a deferred task. await scope.UsingAsync(async scope => { var logger = scope.ServiceProvider.GetService <ILogger <ShellScope> >(); try { await task(scope); } catch (Exception e) { logger?.LogError(e, "Error while processing deferred task '{TaskName}' on tenant '{TenantName}'.", task.GetType().FullName, ShellContext.Settings.Name); await scope.HandleExceptionAsync(e); } }, activateShell : false); } } }