private async Task <DispatchingResult> Dispatch(ProjectionDescriptor descriptor, List <MessageEnvelope> envelopes, CancellationToken token) { if (descriptor.IsDropped()) { return(DispatchingResult.StillDropped(descriptor)); } var sw = new Stopwatch(); var context = new ProjectingContext(MaxProjectingRetries, descriptor.Checkpoint.Position); var anyDispatched = false; try { sw.Start(); using (var scope = this.NewTransactionScope()) { foreach (var envelope in envelopes) { if (!descriptor.CanDispatch(envelope.Message.GetType(), envelope.Meta.MessagePosition)) { continue; } context.Reset(); if (await DispatchProjection(descriptor, envelope, context).NotOnCapturedContext()) { descriptor.Checkpoint.Position = envelope.Meta.MessagePosition; anyDispatched = true; } } await UpdateCheckpoint(descriptor.Checkpoint, descriptor.UndropRequested, token).NotOnCapturedContext(); scope.Complete(); } sw.Stop(); return(DispatchingResult.Dispatched(descriptor, envelopes.Count, sw.ElapsedMilliseconds, anyDispatched)); } catch (Exception e) // error in batch { sw.Stop(); descriptor.Checkpoint.Position = context.StartingBatchAtPosition; // restoring position await UpdateCheckpoint(descriptor.Checkpoint, descriptor.UndropRequested, token).NotOnCapturedContext(); return(DispatchingResult.DroppedOnException(descriptor, envelopes.Count, sw.ElapsedMilliseconds, e)); } }