void SendBatchOnceEventIsPersisted(PartitionUpdateEvent evt, EffectTracker effects, Batch batch) { // put the messages in the outbox where they are kept until actually sent var commitPosition = evt.NextCommitLogPosition; // Update the ready to send timestamp to check the delay caused // by non-speculation evt.ReadyToSendTimestamp = this.Partition.CurrentTimeMs; this.Outbox[commitPosition] = batch; batch.Position = commitPosition; batch.Partition = this.Partition; if (!effects.IsReplaying) { if (!this.Partition.Settings.PersistStepsFirst) { // we must not send messages until this step has been persisted evt.OutboxBatch = batch; DurabilityListeners.Register(evt, this); } else { // we can send the messages now this.Send(batch); } } }
void Send(Batch batch) { // now that we know the sending event is persisted, we can send the messages foreach (var outmessage in batch.OutgoingMessages) { DurabilityListeners.Register(outmessage, batch); outmessage.OriginPartition = this.Partition.PartitionId; outmessage.OriginPosition = batch.Position; //outmessage.SentTimestampUnixMs = DateTimeOffset.Now.ToUnixTimeMilliseconds(); this.Partition.Send(outmessage); } }
protected override async Task Process(IList <PartitionEvent> batch) { try { var effects = new EffectTracker( this.partition, this.ApplyToStore, () => (this.commitPosition, this.inputQueuePosition) ); if (batch.Count != 0) { foreach (var partitionEvent in batch) { // record the current time, for measuring latency in the event processing pipeline partitionEvent.IssuedTimestamp = this.partition.CurrentTimeMs; try { switch (partitionEvent) { case PartitionUpdateEvent updateEvent: updateEvent.NextCommitLogPosition = this.commitPosition + 1; await effects.ProcessUpdate(updateEvent).ConfigureAwait(false); DurabilityListeners.ConfirmDurable(updateEvent); if (updateEvent.NextCommitLogPosition > 0) { this.partition.Assert(updateEvent.NextCommitLogPosition > this.commitPosition); this.commitPosition = updateEvent.NextCommitLogPosition; } break; case PartitionReadEvent readEvent: readEvent.OnReadIssued(this.partition); if (readEvent.Prefetch.HasValue) { var prefetchTarget = this.GetOrAdd(readEvent.Prefetch.Value); effects.ProcessReadResult(readEvent, readEvent.Prefetch.Value, prefetchTarget); } var readTarget = this.GetOrAdd(readEvent.ReadTarget); effects.ProcessReadResult(readEvent, readEvent.ReadTarget, readTarget); break; case PartitionQueryEvent queryEvent: var instances = this.QueryOrchestrationStates(queryEvent.InstanceQuery); var backgroundTask = Task.Run(() => effects.ProcessQueryResultAsync(queryEvent, instances.ToAsyncEnumerable())); break; default: throw new InvalidCastException("could not cast to neither PartitionReadEvent nor PartitionUpdateEvent"); } if (partitionEvent.NextInputQueuePosition > 0) { this.partition.Assert(partitionEvent.NextInputQueuePosition > this.inputQueuePosition); this.inputQueuePosition = partitionEvent.NextInputQueuePosition; } } catch (Exception e) { this.partition.ErrorHandler.HandleError(nameof(Process), $"Encountered exception while processing event {partitionEvent}", e, false, false); } } } } catch (Exception e) { this.logger.LogError("Exception in MemoryQueue BatchWorker: {exception}", e); } }