/// <summary> /// Processes the <see cref="snapshot_complete"/> message. Only snapshot_complete(s) from user's sessions should be processed /// </summary> /// <param name="snapshotCompleted">The <see cref="snapshot_complete"/> message received on the system user's session</param> /// <param name="interest">The <see cref="MessageInterest"/> associated with the session which received the message</param> /// <returns>A <see cref="ProducerRecoveryStatus"/> specifying the new status of the manager or null reference if no change is needed</returns> private ProducerRecoveryStatus?ProcessSnapshotCompleteMessage(snapshot_complete snapshotCompleted, MessageInterest interest) { URN eventId; if (_producer.EventRecoveries.TryRemove(snapshotCompleted.request_id, out eventId)) { ExecutionLog.Info($"Recovery with requestId={snapshotCompleted.request_id} for producer={Producer.Id}, eventId={eventId} completed."); EventRecoveryCompleted?.Invoke(this, new EventRecoveryCompletedEventArgs(snapshotCompleted.request_id, eventId)); return(null); } //The snapshot message not for us if (!_recoveryOperation.IsRunning || !_recoveryOperation.RequestId.HasValue || _recoveryOperation.RequestId.Value != snapshotCompleted.RequestId) { return(null); } //Debug.Assert(Status == ProducerRecoveryStatus.Started); RecoveryResult recoveryResult; ExecutionLog.Debug($"SnapshotComplete[{"requestId" + snapshotCompleted.request_id}] for producer=[{"id=" + Producer.Id}] on session {interest.Name} received"); if (!_recoveryOperation.TryComplete(interest, out recoveryResult)) { //The recovery is not complete, nothing to do. ExecutionLog.Debug($"Recovery with requestId={snapshotCompleted.request_id} for producer={Producer.Id} is not yet completed. Waiting for snapshots from other sessions"); return(null); } // The recovery operation completed. Check the result and act accordingly if (recoveryResult.Success) { // the recovery was interrupted if (recoveryResult.InterruptedAt.HasValue) { ExecutionLog.Warn($"Recovery with requestId={snapshotCompleted.request_id} for producer={Producer.Id} completed with interruption at:{recoveryResult.InterruptedAt.Value}"); _producer.SetLastTimestampBeforeDisconnect(recoveryResult.InterruptedAt.Value); return(ProducerRecoveryStatus.Error); } // the recovery was not interrupted var recoveryDuration = TimeProviderAccessor.Current.Now - recoveryResult.StartTime; ExecutionLog.Info($"Recovery with requestId={snapshotCompleted.request_id} for producer={Producer.Id} completed in {recoveryDuration.TotalSeconds} sec."); _producer.SetLastTimestampBeforeDisconnect(SdkInfo.FromEpochTime(snapshotCompleted.timestamp)); return(_timestampTracker.IsBehind ? ProducerRecoveryStatus.Delayed : ProducerRecoveryStatus.Completed); } // The recovery operation timed-out var timeOutDuration = TimeProviderAccessor.Current.Now - recoveryResult.StartTime; ExecutionLog.Warn($"Recovery with requestId={snapshotCompleted.RequestId} timed out after:{timeOutDuration}"); return(ProducerRecoveryStatus.Error); }
/// <summary> /// Handles the event recovery completion of a specific recovery manager /// </summary> /// <param name="sender">An <see cref="object"/> representation of a <see cref="IProducerRecoveryManager"/> instance whose status has changed.</param> /// <param name="e">The <see cref="EventRecoveryCompletedEventArgs"/>Additional information about the event.</param> private void OnRecoveryTrackerEventRecoveryCompleted(object sender, EventRecoveryCompletedEventArgs e) { EventRecoveryCompleted?.Invoke(this, e); }