public async Task OutExceptionPModeInformationIsCorrectlyPersisted()
        {
            long savedId;

            const string pmodeId      = "pmode-id1";
            const string pmodeContent = "<pmode></pmode>";

            using (var db = GetDataStoreContext())
            {
                var outException = OutException.ForEbmsMessageId("message-id", "some-error-happened");
                outException.SetPModeInformation(pmodeId, pmodeContent);

                db.OutExceptions.Add(outException);

                await db.SaveChangesAsync();

                savedId = outException.Id;

                Assert.NotEqual(default(long), savedId);
            }

            using (var db = GetDataStoreContext())
            {
                var outException = db.OutExceptions.FirstOrDefault(i => i.Id == savedId);

                Assert.NotNull(outException);
                Assert.Equal(pmodeId, outException.PModeId);
                Assert.Equal(pmodeContent, outException.PMode);
            }
        }
Example #2
0
        /// <summary>
        /// Handles the execution exception.
        /// </summary>
        /// <param name="exception">The exception.</param>
        /// <param name="context">The message context.</param>
        /// <returns></returns>
        public async Task <MessagingContext> HandleExecutionException(Exception exception, MessagingContext context)
        {
            Logger.Error($"Exception occured while executing Steps: {exception.Message}");
            Logger.Trace(exception.StackTrace);

            if (exception.InnerException != null)
            {
                Logger.Error(exception.InnerException.Message);
                Logger.Trace(exception.InnerException.StackTrace);
            }

            string ebmsMessageId = await GetEbmsMessageId(context);

            using (DatastoreContext db = _createContext())
            {
                await db.TransactionalAsync(async ctx =>
                {
                    var repository = new DatastoreRepository(ctx);
                    var service    = new ExceptionService(_configuration, repository, _bodyStore);

                    OutException entity =
                        context.SubmitMessage != null
                            ? await service.InsertOutgoingSubmitExceptionAsync(exception, context.SubmitMessage, context.SendingPMode)
                            : await service.InsertOutgoingAS4MessageExceptionAsync(exception, ebmsMessageId, context.MessageEntityId, context.SendingPMode);

                    await ctx.SaveChangesAsync();

                    service.InsertRelatedRetryReliability(entity, context.SendingPMode?.ExceptionHandling?.Reliability);
                    await ctx.SaveChangesAsync();
                });
            }

            return(new MessagingContext(exception));
        }
Example #3
0
        private static OutException CreateOutException(string ebmsMessageId, DateTimeOffset insertionTime)
        {
            OutException ex = OutException.ForEbmsMessageId(ebmsMessageId, exception: string.Empty);

            ex.InsertionTime = insertionTime;

            return(ex);
        }
Example #4
0
        /// <summary>
        /// Insert an <see cref="OutException"/> based on an exception that occured during an outgoing operation for which we do not have a valid/complete message.
        /// Example: transformation.
        /// </summary>
        /// <param name="exception">The exception which message will be inserted.</param>
        /// <param name="messageStream">The stream that represents the message which caused the exception.</param>
        public async Task InsertOutgoingExceptionAsync(Exception exception, Stream messageStream)
        {
            string location = await _bodyStore.SaveAS4MessageStreamAsync(
                _config.OutExceptionStoreLocation,
                messageStream);

            OutException entity = OutException.ForMessageBody(location, exception);

            _repository.InsertOutException(entity);
        }
Example #5
0
        /// <summary>
        /// Insert a given <see cref="OutException"/> into the Data store.
        /// </summary>
        /// <param name="outException"></param>
        public void InsertOutException(OutException outException)
        {
            if (outException == null)
            {
                throw new ArgumentNullException(nameof(outException));
            }

            outException.InsertionTime    = DateTimeOffset.Now;
            outException.ModificationTime = DateTimeOffset.Now;

            _datastoreContext.OutExceptions.Add(outException);
        }
Example #6
0
        /// <summary>
        /// Updates a single <see cref="OutException"/> entity for given <paramref name="id"/>.
        /// </summary>
        /// <param name="id">The identifier to locate the <see cref="OutException"/> entity</param>
        /// <param name="update">The update function to change the located <see cref="OutException"/> entity</param>
        public void UpdateOutException(long id, Action <OutException> update)
        {
            if (update == null)
            {
                throw new ArgumentNullException(nameof(update));
            }

            OutException entity = _datastoreContext.OutExceptions.Single(ex => ex.Id == id);

            update(entity);

            entity.ModificationTime = DateTimeOffset.Now;
        }
        private async Task <MessagingContext> HandleNotifyException(Exception exception, MessagingContext context)
        {
            Logger.Error(exception.Message);

            using (var dbContext = _createContext())
            {
                var repository = new DatastoreRepository(dbContext);

                if (context.NotifyMessage.EntityType == typeof(InMessage) ||
                    context.NotifyMessage.EntityType == typeof(InException))
                {
                    var inException = InException.ForEbmsMessageId(context.EbmsMessageId, exception);
                    repository.InsertInException(inException);

                    if (context.NotifyMessage.EntityType == typeof(InMessage))
                    {
                        Logger.Debug("Fatal fail in notification, set InMessage(s).Status=Exception");
                        repository.UpdateInMessage(context.EbmsMessageId, i => i.SetStatus(InStatus.Exception));
                    }
                }
                else if (context.NotifyMessage.EntityType != typeof(OutMessage) ||
                         context.NotifyMessage.EntityType == typeof(OutException))
                {
                    var outException = OutException.ForEbmsMessageId(context.EbmsMessageId, exception);
                    repository.InsertOutException(outException);

                    if (context.NotifyMessage.EntityType == typeof(OutMessage) &&
                        context.MessageEntityId != null)
                    {
                        Logger.Debug("Fatal fail in notification, set OutMessage.Status=Exception");
                        repository.UpdateOutMessage(
                            context.MessageEntityId.Value,
                            o => o.SetStatus(OutStatus.Exception));
                    }
                }

                if (context.MessageEntityId != null)
                {
                    Logger.Debug("Abort retry operation due to fatal notification exception, set Status=Completed");
                    repository.UpdateRetryReliability(
                        context.MessageEntityId.Value,
                        r => r.Status = RetryStatus.Completed);
                }

                await dbContext.SaveChangesAsync();
            }

            return(new MessagingContext(exception));
        }
        public async void ThenOutExceptionIsTransformedToNotifyEnvelope()
        {
            // Arrange
            ReceivedEntityMessage receivedMessage = CreateReceivedExceptionMessage(OutException.ForEbmsMessageId("id", "error"), Operation.ToBeNotified);
            var transformer = new NotifyMessageTransformer();

            // Act
            MessagingContext result = await transformer.TransformAsync(receivedMessage);

            // Assert
            Assert.NotNull(result.NotifyMessage);
            Assert.Equal(
                ((ExceptionEntity)receivedMessage.Entity).EbmsRefToMessageId,
                result.NotifyMessage.MessageInfo.RefToMessageId);
        }
            public async Task ThenInsertOutExceptionSucceeds()
            {
                // Arrange
                var outException = OutException.ForEbmsMessageId($"outex-{Guid.NewGuid()}", "error");

                // Act
                using (DatastoreContext context = GetDataStoreContext())
                {
                    new DatastoreRepository(context).InsertOutException(outException);

                    await context.SaveChangesAsync();
                }

                // Assert
                GetDataStoreContext.AssertOutException(outException.EbmsRefToMessageId, Assert.NotNull);
            }
Example #10
0
        public async Task OutException_Is_Set_To_Notified_When_Retry_Happen_Within_Allowed_MaxRetry(
            HttpStatusCode secondAttempt,
            Operation expected)
        {
            await TestComponentWithSettings(
                "outexception_notify_reliability_settings.xml",
                async (settings, as4Msh) =>
            {
                // Arrange
                var handler = new OutboundExceptionHandler(
                    () => new DatastoreContext(as4Msh.GetConfiguration()),
                    as4Msh.GetConfiguration(),
                    Registry.Instance.MessageBodyStore);

                const string url     = "http://localhost:7070/business/outexception/";
                string ebmsMessageId = $"entity-{Guid.NewGuid()}";

                var spy = new DatabaseSpy(as4Msh.GetConfiguration());
                //var entity = new OutMessage(ebmsMessageId);
                //spy.InsertOutMessage(entity);

                // Act
                await handler.HandleExecutionException(
                    new Exception("This is an test exception"),
                    new MessagingContext(new SubmitMessage())
                {
                    SendingPMode = NotifySendingPMode(url)
                });

                // Arrange
                SimulateNotifyFailureOnFirstAttempt(url, secondAttempt);


                OutException notified =
                    await PollUntilPresent(
                        () => spy.GetOutExceptions(
                            ex => ex.Operation == expected).FirstOrDefault(),
                        timeout: TimeSpan.FromSeconds(10));

                Entities.RetryReliability referenced = await PollUntilPresent(
                    () => spy.GetRetryReliabilityFor(r => r.RefToOutExceptionId == notified.Id),
                    timeout: TimeSpan.FromSeconds(5));
                Assert.Equal(RetryStatus.Completed, referenced.Status);
            });
        }
Example #11
0
        /// <summary>
        /// Insert an <see cref="OutException"/> based on an exception that occured during the outgoing processing of an <see cref="AS4Message"/>.
        /// </summary>
        /// <param name="exception">The exception which message will be inserted.</param>
        /// <param name="ebmsMessageId">The primary message id of the <see cref="AS4Message"/> that caused the exception</param>
        /// <param name="entityId">The primary key of the stored record to which the mesage is refering to.</param>
        /// <param name="pmode">The PMode that was used during the processing of the message.</param>
        public async Task <OutException> InsertOutgoingAS4MessageExceptionAsync(
            Exception exception,
            string ebmsMessageId,
            long?entityId,
            SendingProcessingMode pmode)
        {
            OutException entity =
                OutException
                .ForEbmsMessageId(ebmsMessageId, exception)
                .SetOperationFor(pmode?.ExceptionHandling);

            await entity.SetPModeInformationAsync(pmode);

            _repository.InsertOutException(entity);

            if (entityId.HasValue)
            {
                _repository.UpdateOutMessage(entityId.Value, m => m.SetStatus(OutStatus.Exception));
            }

            return(entity);
        }
Example #12
0
        /// <summary>
        /// Insert an <see cref="OutException"/> based on an exception that occured during the outgoing Submit operation.
        /// </summary>
        /// <param name="exception">The exception which message will be inserted.</param>
        /// <param name="submit">The message that caused the exception.</param>
        /// <param name="pmode">The PMode that was being used during the Submit operation.</param>
        public async Task <OutException> InsertOutgoingSubmitExceptionAsync(
            Exception exception,
            SubmitMessage submit,
            SendingProcessingMode pmode)
        {
            Stream stream = await AS4XmlSerializer.ToStreamAsync(submit);

            string location = await _bodyStore.SaveAS4MessageStreamAsync(
                _config.OutExceptionStoreLocation,
                stream);

            OutException entity =
                OutException
                .ForMessageBody(location, exception)
                .SetOperationFor(pmode?.ExceptionHandling);

            await entity.SetPModeInformationAsync(pmode);

            _repository.InsertOutException(entity);

            return(entity);
        }
Example #13
0
        /// <summary>
        /// Insert a <see cref="RetryReliability"/> record for an stored <see cref="OutException"/> record.
        /// </summary>
        /// <param name="referenced">The referenced exception record.</param>
        /// <param name="reliability">Reliability to populate the record with retry information.</param>
        public void InsertRelatedRetryReliability(OutException referenced, RetryReliability reliability)
        {
            if (referenced == null)
            {
                throw new ArgumentNullException(nameof(referenced));
            }

            if (referenced.Id <= 0)
            {
                throw new InvalidOperationException(
                          "Requires to have a stored OutException to insert a referenced RetryReliability record");
            }

            if (reliability != null && reliability.IsEnabled)
            {
                var r = Entities.RetryReliability.CreateForOutException(
                    refToOutExceptionId: referenced.Id,
                    maxRetryCount: reliability.RetryCount,
                    retryInterval: reliability.RetryInterval.AsTimeSpan(),
                    type: RetryType.Notification);

                _repository.InsertRetryReliability(r);
            }
        }
Example #14
0
 /// <summary>
 /// Inserts the given <see cref="OutException"/> into the <see cref="DatastoreContext"/>.
 /// </summary>
 /// <param name="ex">The message.</param>
 public void InsertOutException(OutException ex) => ChangeContext(ctx => ctx.OutExceptions.Add(ex));
        protected virtual void SetupDataStore()
        {
            using (datastoreContext = new DatastoreContext(options, StubConfig.Default))
            {
                string pmodeString = AS4XmlSerializer.ToString(pmode);
                string pmodeId     = pmode.Id;

                {
                    var message = new InMessage(ebmsMessageId: InEbmsMessageId1)
                    {
                        EbmsRefToMessageId = InEbmsRefToMessageId1,
                        InsertionTime      = DateTime.UtcNow.AddMinutes(-1),
                    };
                    message.SetStatus(InStatus.Created);
                    message.SetPModeInformation(pmodeId, pmodeString);
                    datastoreContext.InMessages.Add(message);
                }

                {
                    var message = new InMessage(ebmsMessageId: InEbmsMessageId2)
                    {
                        EbmsRefToMessageId = InEbmsRefToMessageId2,
                        InsertionTime      = DateTime.UtcNow.AddMinutes(-1)
                    };
                    message.SetStatus(InStatus.Received);
                    datastoreContext.InMessages.Add(message);
                }

                {
                    var message = new OutMessage(OutEbmsMessageId1)
                    {
                        EbmsRefToMessageId = OutEbmsRefToMessageId1,
                        InsertionTime      = DateTime.UtcNow.AddMinutes(-1)
                    };
                    message.SetStatus(OutStatus.Created);

                    datastoreContext.OutMessages.Add(message);
                }

                {
                    var message = new OutMessage(OutEbmsMessageId2)
                    {
                        EbmsRefToMessageId = OutEbmsRefToMessageId2,

                        InsertionTime = DateTime.UtcNow.AddMinutes(-1)
                    };
                    message.SetStatus(OutStatus.Created);
                    datastoreContext.OutMessages.Add(message);
                }

                InException inEx1 = Entities.InException.ForEbmsMessageId(InEbmsMessageId1, InException);
                inEx1.InsertionTime = DateTime.UtcNow.AddMinutes(-1);
                datastoreContext.InExceptions.Add(inEx1);

                InException inEx2 = Entities.InException.ForEbmsMessageId(InEbmsMessageId1, InException);
                inEx2.InsertionTime = DateTime.UtcNow.AddMinutes(-1);
                datastoreContext.InExceptions.Add(inEx2);

                InException inEx3 = Entities.InException.ForMessageBody(MessageLocation, InException);
                inEx3.InsertionTime = DateTime.UtcNow.AddMinutes(-1);
                datastoreContext.InExceptions.Add(inEx3);

                OutException outEx1 = Entities.OutException.ForEbmsMessageId(OutEbmsRefToMessageId1, InException);
                outEx1.InsertionTime = DateTime.UtcNow.AddMinutes(-1);
                datastoreContext.OutExceptions.Add(outEx1);

                OutException outEx2 = OutException.ForEbmsMessageId(InEbmsRefToMessageId1, Exception);
                outEx2.InsertionTime = DateTime.UtcNow.AddMinutes(-1);
                datastoreContext.OutExceptions.Add(outEx2);

                OutException outEx3 = OutException.ForMessageBody(MessageLocation, Exception);
                outEx3.InsertionTime = DateTime.UtcNow.AddMinutes(-1);
                datastoreContext.OutExceptions.Add(outEx3);

                datastoreContext.SaveChanges();

                foreach (var inMessage in datastoreContext.InMessages)
                {
                    inMessage.SetPModeInformation(pmodeId, pmodeString);
                }

                foreach (var outMessage in datastoreContext.OutMessages)
                {
                    outMessage.SetPModeInformation(pmodeId, pmodeString);
                }

                foreach (var inException in datastoreContext.InExceptions)
                {
                    inException.SetPModeInformation(pmodeId, pmodeString);
                }

                foreach (var outException in datastoreContext.OutExceptions)
                {
                    outException.SetPModeInformation(pmodeId, pmodeString);
                }

                datastoreContext.SaveChanges();
            }
        }
        /// <summary>
        /// Inserts the out exception.
        /// </summary>
        /// <param name="createContext">The create context.</param>
        /// <param name="outException">The out exception.</param>
        public static OutException InsertOutException(this Func <DatastoreContext> createContext, OutException outException)
        {
            using (DatastoreContext context = createContext())
            {
                context.OutExceptions.Add(outException);
                context.SaveChanges();

                return(outException);
            }
        }