private void HandleReplayMessages(ReplayMessages message)
{
var replyTo = _isReplayFilterEnabled
? Context.ActorOf(ReplayFilter.Props(message.PersistentActor, _replayFilterMode, _replayFilterWindowSize,
_replayFilterMaxOldWriters, _replayDebugEnabled))
: message.PersistentActor;
var context = Context;
var readHighestSequenceNrFrom = Math.Max(0, message.FromSequenceNr - 1);
var promise = new TaskCompletionSource<long>();
_breaker
.WithCircuitBreaker(() => ReadHighestSequenceNrAsync(message.PersistenceId, readHighestSequenceNrFrom))
.ContinueWith(t =>
{
if (!t.IsFaulted && !t.IsCanceled)
{
var highSequenceNr = t.Result;
var toSequenceNr = Math.Min(message.ToSequenceNr, highSequenceNr);
if (highSequenceNr == 0 || message.FromSequenceNr > toSequenceNr)
{
promise.SetResult(highSequenceNr);
}
else
{
// Send replayed messages and replay result to persistentActor directly. No need
// to resequence replayed messages relative to written and looped messages.
// not possible to use circuit breaker here
ReplayMessagesAsync(context, message.PersistenceId, message.FromSequenceNr, toSequenceNr,
message.Max, p =>
{
if (!p.IsDeleted) // old records from pre 1.5 may still have the IsDeleted flag
{
foreach (var adaptedRepresentation in AdaptFromJournal(p))
{
replyTo.Tell(new ReplayedMessage(adaptedRepresentation), ActorRefs.NoSender);
}
}
})
.ContinueWith(replayTask =>
{
if (!replayTask.IsFaulted && !replayTask.IsCanceled)
promise.SetResult(highSequenceNr);
else
promise.SetException(replayTask.IsFaulted
? TryUnwrapException(replayTask.Exception)
: new OperationCanceledException(
"ReplayMessagesAsync canceled, possibly due to timing out."));
}, _continuationOptions);
}
}
else
{
promise.SetException(t.IsFaulted
? TryUnwrapException(t.Exception)
: new OperationCanceledException(
"ReadHighestSequenceNrAsync canceled, possibly due to timing out."));
}
}, _continuationOptions);
promise.Task
.ContinueWith(t => !t.IsFaulted ? (object) new RecoverySuccess(t.Result) : new ReplayMessagesFailure(TryUnwrapException(t.Exception)), _continuationOptions)
.PipeTo(replyTo)
.ContinueWith(t =>
{
if (!t.IsFaulted && CanPublish) context.System.EventStream.Publish(message);
}, _continuationOptions);
}