public async Task OnCommandAsync(IInvalidateCommand command, CommandContext context, CancellationToken cancellationToken) { var skip = !IsEnabled || !InvalidationInfoProvider.RequiresInvalidation(command.UntypedCommand) || Computed.IsInvalidating(); if (skip) { await context.InvokeRemainingHandlersAsync(cancellationToken).ConfigureAwait(false); return; } using var _ = Computed.Invalidate(); var finalHandler = context.ExecutionState.FindFinalHandler(); if (finalHandler != null) { if (Log.IsEnabled(LogLevel.Debug)) { Log.LogDebug("Invalidating via dedicated command handler: {0}", command); } await context.InvokeRemainingHandlersAsync(cancellationToken).ConfigureAwait(false); } else { if (Log.IsEnabled(LogLevel.Debug)) { Log.LogDebug("Invalidating via shared command handler: {0}", command); } await context.Commander.RunAsync(command.UntypedCommand, cancellationToken).ConfigureAwait(false); } }
public async Task OnCommandAsync(ICommand command, CommandContext context, CancellationToken cancellationToken) { var operation = context.OuterContext != null?context.Items.TryGet <IOperation>() : null; var mustBeLogged = operation != null && // Should be a nested context inside a context w/ operation InvalidationInfoProvider.RequiresInvalidation(command) && // Command requires invalidation !Computed.IsInvalidating(); if (!mustBeLogged) { await context.InvokeRemainingHandlersAsync(cancellationToken).ConfigureAwait(false); return; } var operationItems = operation !.Items; var commandItems = new OptionSet(); operation.Items = commandItems; Exception?error = null; try { await context.InvokeRemainingHandlersAsync(cancellationToken).ConfigureAwait(false); } catch (Exception?e) { error = e; throw; }
protected virtual async ValueTask InvokeNestedCommands( CommandContext context, IOperation operation, ImmutableList <NestedCommandEntry> nestedCommands, CancellationToken cancellationToken) { foreach (var commandEntry in nestedCommands) { var(command, items) = commandEntry; if (command is IServerSideCommand serverSideCommand) { serverSideCommand.MarkServerSide(); // Server-side commands should be marked as such } if (InvalidationInfoProvider.RequiresInvalidation(command)) { operation.Items = items; await context.Commander.Call(command, cancellationToken).ConfigureAwait(false); } var subcommands = items.GetOrDefault(ImmutableList <NestedCommandEntry> .Empty); if (!subcommands.IsEmpty) { await InvokeNestedCommands(context, operation, subcommands, cancellationToken); } } }
public async Task OnCommandAsync(ICommand command, CommandContext context, CancellationToken cancellationToken) { var skip = !IsEnabled || context.OuterContext != null || // Should be top-level command command is IInvalidateCommand || // Second handler here will take care of it Computed.IsInvalidating(); if (skip) { await context.InvokeRemainingHandlersAsync(cancellationToken).ConfigureAwait(false); return; } if (InvalidationInfoProvider.RequiresInvalidation(command)) { context.Items.Set(InvalidateCommand.New(command)); } await context.InvokeRemainingHandlersAsync(cancellationToken).ConfigureAwait(false); var invalidate = context.Items.TryGet <IInvalidateCommand>(); if (invalidate != null) { await context.Commander.RunAsync(invalidate, true, default).ConfigureAwait(false); } }
public async Task OnCommandAsync(ICompletion command, CommandContext context, CancellationToken cancellationToken) { var originalCommand = command.UntypedCommand; var requiresInvalidation = InvalidationInfoProvider.RequiresInvalidation(originalCommand) && !Computed.IsInvalidating(); if (!requiresInvalidation) { await context.InvokeRemainingHandlersAsync(cancellationToken).ConfigureAwait(false); return; } var oldOperation = context.Items.TryGet <IOperation>(); var operation = command.Operation; context.SetOperation(operation); var invalidateScope = Computed.Invalidate(); try { var logEnabled = LogLevel != LogLevel.None && Log.IsEnabled(LogLevel); var finalHandler = context.ExecutionState.FindFinalHandler(); if (finalHandler != null) { if (logEnabled) { Log.Log(LogLevel, "Invalidating via dedicated command handler for '{CommandType}'", command.GetType()); } await context.InvokeRemainingHandlersAsync(cancellationToken).ConfigureAwait(false); } else { if (logEnabled) { Log.Log(LogLevel, "Invalidating via shared command handler for '{CommandType}'", originalCommand.GetType()); } await context.Commander.CallAsync(originalCommand, cancellationToken).ConfigureAwait(false); } var operationItems = operation.Items; try { var nestedCommands = operationItems.GetOrDefault(ImmutableList <NestedCommandEntry> .Empty); if (!nestedCommands.IsEmpty) { await InvokeNestedCommandsAsync(context, operation, nestedCommands, cancellationToken); } } finally { operation.Items = operationItems; } } finally { context.SetOperation(oldOperation); invalidateScope.Dispose(); } }
public async Task OnCommandAsync(IInvalidateCommand command, CommandContext context, CancellationToken cancellationToken) { var skip = !IsEnabled || !InvalidationInfoProvider.RequiresInvalidation(command.UntypedCommand) || Computed.IsInvalidating(); if (skip) { await context.InvokeRemainingHandlersAsync(cancellationToken).ConfigureAwait(false); return; } // Copying IOperation.Items to CommandContext.Items var operation = command.Operation; var operationItems = operation?.Items.Items; if (operationItems != null) { foreach (var(key, value) in operationItems) { if (value is IOperationItem) { context.Items[key] = value; } } } var logEnabled = LogLevel != LogLevel.None && Log.IsEnabled(LogLevel); using var _ = Computed.Invalidate(); var finalHandler = context.ExecutionState.FindFinalHandler(); if (finalHandler != null) { if (logEnabled) { Log.Log(LogLevel, "Invalidating via dedicated command handler: {0}", command); } await context.InvokeRemainingHandlersAsync(cancellationToken).ConfigureAwait(false); } else { if (logEnabled) { Log.Log(LogLevel, "Invalidating via shared command handler: {0}", command); } await context.Commander.RunAsync(command.UntypedCommand, cancellationToken).ConfigureAwait(false); } }
public virtual void OnOperationCompleted(IOperation operation) { if (operation.AgentId == AgentInfo.Id.Value) { // Local operations are invalidated by InvalidationHandler return; } if (!(operation.Command is ICommand command)) { return; } if (!InvalidationInfoProvider.RequiresInvalidation(command)) { return; } if (Log.IsEnabled(LogLevel.Debug)) { Log.LogDebug("Invalidating operation: agent {0}, command {1}", operation.AgentId, command); } Commander.Start(InvalidateCommand.New(command, operation), true); }
public async Task OnCommand(ICompletion command, CommandContext context, CancellationToken cancellationToken) { var originalCommand = command.UntypedCommand; var requiresInvalidation = InvalidationInfoProvider.RequiresInvalidation(originalCommand) && !Computed.IsInvalidating(); if (!requiresInvalidation) { await context.InvokeRemainingHandlers(cancellationToken).ConfigureAwait(false); return; } var oldOperation = context.Items.TryGet <IOperation>(); var operation = command.Operation; context.SetOperation(operation); var invalidateScope = Computed.Invalidate(); try { var finalHandler = context.ExecutionState.FindFinalHandler(); var useOriginalCommandHandler = finalHandler == null || finalHandler.GetHandlerService(command, context) is CatchAllCompletionHandler; if (useOriginalCommandHandler) { if (InvalidationInfoProvider.IsReplicaServiceCommand(originalCommand)) { if (IsLoggingEnabled) { Log.Log(LogLevel, "No invalidation for replica service command '{CommandType}'", originalCommand.GetType()); } return; } if (IsLoggingEnabled) { Log.Log(LogLevel, "Invalidating via original command handler for '{CommandType}'", originalCommand.GetType()); } await context.Commander.Call(originalCommand, cancellationToken).ConfigureAwait(false); } else { if (IsLoggingEnabled) { Log.Log(LogLevel, "Invalidating via dedicated command handler for '{CommandType}'", command.GetType()); } await context.InvokeRemainingHandlers(cancellationToken).ConfigureAwait(false); } var operationItems = operation.Items; try { var nestedCommands = operationItems.GetOrDefault(ImmutableList <NestedCommandEntry> .Empty); if (!nestedCommands.IsEmpty) { await InvokeNestedCommands(context, operation, nestedCommands, cancellationToken); } } finally { operation.Items = operationItems; } } finally { context.SetOperation(oldOperation); invalidateScope.Dispose(); } }
public async Task OnCommandAsync(ICommand command, CommandContext context, CancellationToken cancellationToken) { var skip = context.OuterContext != null || // Should be top-level command command is IInvalidateCommand || // Second handler here will take care of it Computed.IsInvalidating(); if (skip) { await context.InvokeRemainingHandlersAsync(cancellationToken).ConfigureAwait(false); return; } var tScope = typeof(IDbOperationScope <TDbContext>); if (context.Items[tScope] != null) // Safety check { throw Stl.Internal.Errors.InternalError($"'{tScope}' scope is already provided. Duplicate handler?"); } var logEnabled = LogLevel != LogLevel.None && Log.IsEnabled(LogLevel); await using var scope = Services.GetRequiredService <IDbOperationScope <TDbContext> >(); scope.Command = command; context.Items.Set(scope); if (logEnabled) { Log.Log(LogLevel, "+ Operation started: {0}", command); } IOperation?operation = null; try { await context.InvokeRemainingHandlersAsync(cancellationToken).ConfigureAwait(false); // Building IOperation.Items from CommandContext.Items foreach (var(key, value) in context.Items.Items) { if (value is IOperationItem) { scope.Items = scope.Items.Set(key, value); } } operation = await scope.CommitAsync(cancellationToken); if (logEnabled) { Log.Log(LogLevel, "- Operation succeeded: {0}", command); } } catch (OperationCanceledException) { throw; } catch (Exception e) { Log.LogError(e, "! Operation failed: {0}", command); try { await scope.RollbackAsync(); } catch { // Intended } throw; } if (operation != null) { if (InvalidationInfoProvider?.RequiresInvalidation(command) ?? false) { context.Items.Set(InvalidateCommand.New(command, operation)); } OperationCompletionNotifier?.NotifyCompleted(operation); } }