public void MessageOlderThanRetentionDateWillBeDeleted(string specificSettings) { // Arrange: Insert a "retired" OutMessage with a referenced Reception Awareness. OverrideWithSpecificSettings(specificSettings); IConfig config = EnsureLocalConfigPointsToCreatedDatastore(); string outReferenceId = GenId(), outStandaloneId = GenId(), inMessageId = GenId(), outExceptionId = GenId(), inExceptionId = GenId(); var spy = new DatabaseSpy(config); OutMessage om = CreateOutMessage(outReferenceId, insertionTime: DayBeforeYesterday, type: MessageType.Error); spy.InsertOutMessage(om); spy.InsertRetryReliability(RetryReliability.CreateForOutMessage(om.Id, maxRetryCount: 0, retryInterval: default(TimeSpan), type: RetryType.Send)); spy.InsertOutMessage(CreateOutMessage(outStandaloneId, insertionTime: DayBeforeYesterday, type: MessageType.Receipt)); spy.InsertInMessage(CreateInMessage(inMessageId, DayBeforeYesterday)); spy.InsertOutException(CreateOutException(outExceptionId, DayBeforeYesterday)); spy.InsertInException(CreateInException(inExceptionId, DayBeforeYesterday)); // Act: AS4.NET Component will start the Clean Up Agent. ExerciseStartCleaning(); // Assert: No OutMessage or Reception Awareness entries must be found for a given EbmsMessageId. Assert.Empty(spy.GetOutMessages(outReferenceId, outStandaloneId)); Assert.Null(spy.GetRetryReliabilityFor(r => r.RefToOutMessageId == om.Id)); Assert.Empty(spy.GetInMessages(inMessageId)); Assert.Empty(spy.GetOutExceptions(outExceptionId)); Assert.Empty(spy.GetInExceptions(inExceptionId)); }
/// <summary> /// Inserts the out message. /// </summary> /// <param name="createContext">The create context.</param> /// <param name="message">The message.</param> /// <param name="withReceptionAwareness"></param> /// <returns>The OutMessage that has been inserted</returns> public static OutMessage InsertOutMessage( this Func <DatastoreContext> createContext, OutMessage message, bool withReceptionAwareness = false) { using (DatastoreContext context = createContext()) { context.OutMessages.Add(message); context.SaveChanges(); if (withReceptionAwareness) { context.Add( RetryReliability.CreateForOutMessage( refToOutMessageId: message.Id, maxRetryCount: 0, retryInterval: TimeSpan.Zero, type: RetryType.Send)); context.SaveChanges(); } return(message); } }
private static void UpdateExceptionRetry <T>( SendResult resultOfOperation, T entityToBeRetried, Func <IEnumerable <RetryReliability> > getRetryEntries) where T : ExceptionEntity { // There could be more In/Out Exceptions for a single message, // therefore we should only look for exceptions that are not yet been Notified/DeadLettered. if (entityToBeRetried.Operation == Operation.Notified || entityToBeRetried.Operation == Operation.DeadLettered) { return; } RetryReliability rr = getRetryEntries().FirstOrDefault(); string reftoMessageId = entityToBeRetried.EbmsRefToMessageId == null ? String.Empty : $"[{entityToBeRetried.EbmsRefToMessageId}]"; if (resultOfOperation == SendResult.Success) { Logger.Debug($"Update {typeof(T).Name} {reftoMessageId} with Operation=Notified"); entityToBeRetried.Operation = Operation.Notified; if (rr != null) { rr.Status = RetryStatus.Completed; } } else { if (rr == null) { Logger.Debug($"{typeof(T).Name} NotifyMessage failed during the notification, exhausted retries"); Logger.Debug($"Update {typeof(T).Name} with {{Status=Exception, Operation=DeadLettered}}"); entityToBeRetried.Operation = Operation.DeadLettered; } else if (resultOfOperation == SendResult.RetryableFail) { Logger.Debug($"{typeof(T).Name} NotifyMessage failed this time, will be retried by updating Operation=ToBeRetried"); entityToBeRetried.Operation = Operation.ToBeRetried; rr.Status = RetryStatus.Pending; } else { Logger.Debug($"{typeof(T).Name} NotifyMessage failed during the notification, exhausted retries"); Logger.Debug($"Update {typeof(T).Name} with {{Status=Exception, Operation=DeadLettered}}"); entityToBeRetried.Operation = Operation.DeadLettered; rr.Status = RetryStatus.Completed; } } }
private static void UpdateMessageEntity <T>( SendResult resultOfOperation, T entityToBeRetried, Func <IEnumerable <RetryReliability> > getRetryEntries, Action <T> onCompleted, Action <T> onDeadLettered) where T : MessageEntity { // Only for records that are not yet been completly Notified/DeadLettered should we botter to retry if (entityToBeRetried.Operation == Operation.Notified || entityToBeRetried.Operation == Operation.DeadLettered) { return; } RetryReliability rr = getRetryEntries().FirstOrDefault(); if (resultOfOperation == SendResult.Success) { onCompleted(entityToBeRetried); Logger.Trace("Successful result, so update RetryReliability.Status=Completed"); if (rr != null) { rr.Status = RetryStatus.Completed; } } else { if (rr == null) { Logger.Debug("Message can't be retried because no RetryReliability is configured"); Logger.Debug($"Update {typeof(T).Name} with {{Status=Exception, Operation=DeadLettered}}"); onDeadLettered(entityToBeRetried); entityToBeRetried.Operation = Operation.DeadLettered; } else if (resultOfOperation == SendResult.RetryableFail) { Logger.Debug($"Message failed this time, set for retry by updating {typeof(T).Name}.Operation=ToBeRetried"); entityToBeRetried.Operation = Operation.ToBeRetried; rr.Status = RetryStatus.Pending; } else { Logger.Debug("Message failed this time due to a fatal result during sending"); Logger.Debug($"Update {typeof(T).Name} with Status=Exception, Operation=DeadLettered"); onDeadLettered(entityToBeRetried); entityToBeRetried.Operation = Operation.DeadLettered; rr.Status = RetryStatus.Completed; } } }
/// <summary> /// Inserts the retry reliability information referencing a <see cref="InMessage"/>. /// </summary> /// <param name="reliability">The <see cref="RetryReliability"/> entity to insert</param> public void InsertRetryReliability(RetryReliability reliability) { if (reliability == null) { throw new ArgumentNullException(nameof(reliability)); } reliability.InsertionTime = DateTimeOffset.Now; reliability.ModificationTime = DateTimeOffset.Now; _datastoreContext.RetryReliability.Add(reliability); }
/// <summary> /// Updates a single <see cref="RetryReliability"/> record for a given <paramref name="id"/>. /// </summary> /// <param name="id">The identifier to locate the <see cref="RetryReliability"/> record</param> /// <param name="update">The update function to change the <see cref="RetryReliability"/> record</param> public void UpdateRetryReliability(long id, Action <RetryReliability> update) { if (update == null) { throw new ArgumentNullException(nameof(update)); } RetryReliability rr = _datastoreContext.RetryReliability.SingleOrDefault(r => r.Id == id); if (rr != null) { update(rr); rr.ModificationTime = DateTimeOffset.Now; } }
private static Property TestRelialityForEnabledFlag( bool isEnabled, int retryCount, TimeSpan retryInterval, Func <ReceivingProcessingMode, RetryReliability> getReliability, Action <ReceivingProcessingMode> extraFixtureSetup = null) { return(Prop.ForAll( Gen.Frequency( Tuple.Create(2, Gen.Constant(retryInterval.ToString())), Tuple.Create(1, Arb.From <string>().Generator)) .ToArbitrary(), retryIntervalText => { // Arrange ReceivingProcessingMode pmode = CreateValidPMode(); RetryReliability r = getReliability(pmode); r.IsEnabled = isEnabled; r.RetryCount = retryCount; r.RetryInterval = retryIntervalText; extraFixtureSetup?.Invoke(pmode); // Act ValidationResult result = ReceivingProcessingModeValidator.Instance.Validate(pmode); // Assert bool correctConfigured = retryCount > 0 && r.RetryInterval.AsTimeSpan() > default(TimeSpan); bool expected = !isEnabled && !correctConfigured || !isEnabled || correctConfigured; return expected.Equals(result.IsValid) .Label(result.AppendValidationErrorsToErrorMessage(string.Empty)) .Classify(result.IsValid, "Valid PMode") .Classify(!result.IsValid, "Invalid PMode") .Classify(correctConfigured, "Correct Reliability") .Classify(!correctConfigured, "Incorrect Reliability") .Classify(isEnabled, "Reliability is enabled") .Classify(!isEnabled, "Reliability is disabled"); })); }
/// <summary> /// Inserts the given <see cref="RetryReliability"/> into the <see cref="DatastoreContext"/>. /// </summary> /// <param name="r"></param> public void InsertRetryReliability(RetryReliability r) => ChangeContext(ctx => ctx.RetryReliability.Add(r));
/// <summary> /// Inserts the retry reliability on a given datastore. /// </summary> /// <param name="createContext">The factory containing the datastore to insert the <see cref="RetryReliability"/> instance</param> /// <param name="r">The <see cref="RetryReliability"/> instance to insert</param> public static void InsertRetryReliability(this Func <DatastoreContext> createContext, RetryReliability r) { using (DatastoreContext context = createContext()) { context.RetryReliability.Add(r); context.SaveChanges(); } }