public void Handle(ClientMessage.WriteEventsCompleted message) { _writeDispatcher.Handle(message); }
private IEnumerable <IODispatcherAsync.Step> PerformStartReader() { yield return (_ioDispatcher.BeginUpdateStreamAcl( _cancellationScope, ProjectionNamesBuilder._projectionsControlStream, ExpectedVersion.Any, SystemAccount.Principal, new StreamMetadata(maxAge: ProjectionNamesBuilder.ControlStreamMaxAge), completed => { })); yield return (_ioDispatcher.BeginUpdateStreamAcl( _cancellationScope, ProjectionNamesBuilder._projectionsMasterStream, ExpectedVersion.Any, SystemAccount.Principal, new StreamMetadata(maxAge: ProjectionNamesBuilder.MasterStreamMaxAge), completed => { })); ClientMessage.WriteEventsCompleted writeResult = null; yield return (_ioDispatcher.BeginWriteEvents( _cancellationScope, ProjectionNamesBuilder._projectionsMasterStream, ExpectedVersion.Any, SystemAccount.Principal, new[] { new Event(Guid.NewGuid(), "$response-reader-starting", true, "{}", null) }, completed => writeResult = completed)); if (writeResult.Result != OperationResult.Success) { throw new Exception("Cannot start response reader. Write result: " + writeResult.Result); } var from = writeResult.LastEventNumber; yield return (_ioDispatcher.BeginWriteEvents( _cancellationScope, ProjectionNamesBuilder._projectionsControlStream, ExpectedVersion.Any, SystemAccount.Principal, new[] { new Event(Guid.NewGuid(), "$response-reader-started", true, "{}", null) }, completed => writeResult = completed)); if (writeResult.Result != OperationResult.Success) { throw new Exception("Cannot start response reader. Write result: " + writeResult.Result); } Log.Debug("PROJECTIONS: Finished Starting Projection Manager Response Reader (reads from $projections-$master)"); while (true) { var eof = false; var subscribeFrom = default(TFPos); do { yield return (_ioDispatcher.BeginReadForward( _cancellationScope, ProjectionNamesBuilder._projectionsMasterStream, @from, 10, false, SystemAccount.Principal, completed => { if (completed.Result == ReadStreamResult.Success || completed.Result == ReadStreamResult.NoStream) { @from = completed.NextEventNumber == -1 ? 0 : completed.NextEventNumber; eof = completed.IsEndOfStream; // subscribeFrom is only used if eof subscribeFrom = new TFPos( completed.TfLastCommitPosition, completed.TfLastCommitPosition); if (completed.Result == ReadStreamResult.Success) { foreach (var e in completed.Events) { PublishCommand(e); } } } })); } while (!eof); yield return (_ioDispatcher.BeginSubscribeAwake( _cancellationScope, ProjectionNamesBuilder._projectionsMasterStream, subscribeFrom, message => { })); } }
private async Task Receive(ChannelWriter <BatchAppendResp> writer, ClaimsPrincipal user, bool requiresLeader, CancellationToken cancellationToken) { var pendingWrites = new ConcurrentDictionary <Guid, ClientWriteRequest>(); try { await foreach (var request in _requestStream.ReadAllAsync(cancellationToken)) { try { var correlationId = Uuid.FromDto(request.CorrelationId).ToGuid(); if (request.Options != null) { if (!await _authorizationProvider.CheckAccessAsync(user, WriteOperation.WithParameter( Plugins.Authorization.Operations.Streams.Parameters.StreamId( request.Options.StreamIdentifier)), cancellationToken).ConfigureAwait(false)) { await writer.WriteAsync(new BatchAppendResp { CorrelationId = request.CorrelationId, StreamIdentifier = request.Options.StreamIdentifier, Error = Status.AccessDenied }, cancellationToken).ConfigureAwait(false); continue; } if (request.Options.StreamIdentifier == null) { await writer.WriteAsync(new BatchAppendResp { CorrelationId = request.CorrelationId, StreamIdentifier = request.Options.StreamIdentifier, Error = Status.BadRequest( $"Required field {nameof(request.Options.StreamIdentifier)} not set.") }, cancellationToken).ConfigureAwait(false); continue; } pendingWrites.AddOrUpdate(correlationId, c => FromOptions(c, request.Options, cancellationToken), (_, writeRequest) => writeRequest); } if (!pendingWrites.TryGetValue(correlationId, out var clientWriteRequest)) { continue; } clientWriteRequest.AddEvents(request.ProposedMessages.Select(FromProposedMessage)); if (clientWriteRequest.Size > _maxAppendSize) { pendingWrites.TryRemove(correlationId, out _); await writer.WriteAsync(new BatchAppendResp { CorrelationId = request.CorrelationId, StreamIdentifier = clientWriteRequest.StreamId, Error = Status.MaximumAppendSizeExceeded((uint)_maxAppendSize) }, cancellationToken).ConfigureAwait(false); } if (!request.IsFinal) { continue; } if (!pendingWrites.TryRemove(correlationId, out _)) { continue; } Interlocked.Increment(ref _pending); _publisher.Publish(ToInternalMessage(clientWriteRequest, new CallbackEnvelope(message => { try { writer.TryWrite(ConvertMessage(message)); } catch (Exception ex) { writer.TryComplete(ex); } }), requiresLeader, user, cancellationToken)); BatchAppendResp ConvertMessage(Message message) { var batchAppendResp = message switch { ClientMessage.NotHandled notHandled => new BatchAppendResp { Error = new Status { Details = Any.Pack(new Empty()), Message = (notHandled.Reason, notHandled.AdditionalInfo) switch { (NotHandledReason.NotReady, _) => "Server Is Not Ready", (NotHandledReason.TooBusy, _) => "Server Is Busy", (NotHandledReason.NotLeader or NotHandledReason.IsReadOnly, LeaderInfo leaderInfo) => throw RpcExceptions.LeaderInfo(leaderInfo.HttpAddress, leaderInfo.HttpPort), (NotHandledReason.NotLeader or NotHandledReason.IsReadOnly, _) => "No leader info available in response", _ => $"Unknown {nameof(NotHandledReason)} ({(int)notHandled.Reason})" } } }, ClientMessage.WriteEventsCompleted completed => completed.Result switch { OperationResult.Success => new BatchAppendResp { Success = BatchAppendResp.Types.Success.Completed(completed.CommitPosition, completed.PreparePosition, completed.LastEventNumber), }, OperationResult.WrongExpectedVersion => new BatchAppendResp { Error = Status.WrongExpectedVersion( StreamRevision.FromInt64(completed.CurrentVersion), clientWriteRequest.ExpectedVersion) }, OperationResult.AccessDenied => new BatchAppendResp { Error = Status.AccessDenied }, OperationResult.StreamDeleted => new BatchAppendResp { Error = Status.StreamDeleted(clientWriteRequest.StreamId) }, OperationResult.CommitTimeout or OperationResult.ForwardTimeout or OperationResult.PrepareTimeout => new BatchAppendResp { Error = Status.Timeout }, _ => new BatchAppendResp { Error = Status.Unknown } }, _ => new BatchAppendResp { Error = new Status { Details = Any.Pack(new Empty()), Message = $"Envelope callback expected either {nameof(ClientMessage.WriteEventsCompleted)} or {nameof(ClientMessage.NotHandled)}, received {message.GetType().Name} instead" } } }; batchAppendResp.CorrelationId = Uuid.FromGuid(correlationId).ToDto(); batchAppendResp.StreamIdentifier = new StreamIdentifier { StreamName = ByteString.CopyFromUtf8(clientWriteRequest.StreamId) }; return(batchAppendResp); } } catch (Exception ex) { await writer.WriteAsync(new BatchAppendResp { CorrelationId = request.CorrelationId, StreamIdentifier = request.Options.StreamIdentifier, Error = Status.BadRequest(ex.Message) }, cancellationToken).ConfigureAwait(false); } }
private void WriteStateCompleted(Action <ResolvedEvent, OperationResult> completed, ResolvedEvent ev, ClientMessage.WriteEventsCompleted msg) { _lastParkedEventNumber = msg.LastEventNumber; completed?.Invoke(ev, msg.Result); }
public void Handle(ClientMessage.WriteEventsCompleted message) { _forwardingProxy.TryForwardReply(message.CorrelationId, message, (clientCorrId, m) => m.WithCorrelationId(clientCorrId)); }