예제 #1
0
        /// <summary>
        ///  When overriden, defines the custom behavior to be invoked after attempting to save the specified <paramref name="saga"/>.
        /// </summary>
        /// <param name="saga">The modified <see cref="Saga"/> instance if <paramref name="error"/> is <value>null</value>; otherwise the original <see cref="Saga"/> instance if <paramref name="error"/> is not <value>null</value>.</param>
        /// <param name="context">The current <see cref="SagaContext"/> assocaited with the pending saga modifications.</param>
        /// <param name="error">The <see cref="Exception"/> thrown if the save was unsuccessful; otherwise <value>null</value>.</param>
        public override void PostSave(Saga saga, SagaContext context, Exception error)
        {
            base.PostSave(saga, context, error);

            if (error is ConcurrencyException)
                statistics.IncrementConflictCount();
        }
예제 #2
0
 /// <summary>
 /// Invokes zero or more customized <see cref="PipelineHook.PostSave"/> implementations.
 /// </summary>
 /// <param name="saga">The modified <see cref="Saga"/> instance if <paramref name="error"/> is <value>null</value>; otherwise the original <see cref="Saga"/> instance if <paramref name="error"/> is not <value>null</value>.</param>
 /// <param name="context">The current <see cref="SagaContext"/> assocaited with the pending saga modifications.</param>
 /// <param name="error">The <see cref="Exception"/> thrown if the save was unsuccessful; otherwise <value>null</value>.</param>
 private void InvokePostSaveHooks(Saga saga, SagaContext context, Exception error)
 {
     foreach (var pipelineHook in postSaveHooks)
     {
         Log.Trace("Invoking post-save pipeline hook: {0}", pipelineHook);
         pipelineHook.PostSave(saga, context, error);
     }
 }
예제 #3
0
 /// <summary>
 /// Invokes zero or more customized <see cref="PipelineHook.PreSave"/> implementations.
 /// </summary>
 /// <param name="saga">The saga to be modified by the current <paramref name="context"/>.</param>
 /// <param name="context">The current <see cref="SagaContext"/> associated with the pending saga modifications.</param>
 private void InvokePreSaveHooks(Saga saga, SagaContext context)
 {
     foreach (var pipelineHook in preSaveHooks)
     {
         Log.Trace("Invoking pre-save pipeline hook: {0}", pipelineHook);
         pipelineHook.PreSave(saga, context);
     }
 }
예제 #4
0
 /// <summary>
 /// Invokes zero or more customized <see cref="PipelineHook.PostGet"/> implementations.
 /// </summary>
 /// <param name="saga">The loaded saga instance.</param>
 private void InvokePostGetHooks(Saga saga)
 {
     foreach (var pipelineHook in postGetHooks)
     {
         Log.Trace("Invoking post-get pipeline hook: {0}", pipelineHook);
         pipelineHook.PostGet(saga);
     }
 }
예제 #5
0
        /// <summary>
        /// Attempt to retrieve an existing saga instance identified by the specified <paramref name="type"/> and <paramref name="id"/>.
        /// </summary>
        /// <param name="type">The type of saga to be retrieved.</param>
        /// <param name="id">The correlation id of the saga to be retrieved.</param>
        /// <param name="saga">The <see cref="Saga"/> instance if found; otherwise <value>null</value>.</param>
        public Boolean TryGetSaga(Type type, Guid id, out Saga saga)
        {
            Boolean result;

            InvokePreGetHooks(type, id);

            result = sagaStore.TryGetSaga(type, id, out saga);

            InvokePostGetHooks(saga);

            return(result);
        }
예제 #6
0
        /// <summary>
        /// Save the specified <paramref name="context"/> changes for the given <paramref name="saga"/>.
        /// </summary>
        /// <param name="saga">The current saga version for which the context applies.</param>
        /// <param name="context">The saga context containing the saga changes to be applied.</param>
        public Saga Save(Saga saga, SagaContext context)
        {
            InvokePreSaveHooks(saga, context);

            try
            {
                var result = sagaStore.Save(saga, context);

                InvokePostSaveHooks(result, context, null);

                return(result);
            }
            catch (Exception ex)
            {
                InvokePostSaveHooks(saga, context, ex);
                throw;
            }
        }
예제 #7
0
        /// <summary>
        ///  When overriden, defines the custom behavior to be invoked after attempting to save the specified <paramref name="saga"/>.
        /// </summary>
        /// <param name="saga">The modified <see cref="Saga"/> instance if <paramref name="error"/> is <value>null</value>; otherwise the original <see cref="Saga"/> instance if <paramref name="error"/> is not <value>null</value>.</param>
        /// <param name="context">The current <see cref="SagaContext"/> assocaited with the pending saga modifications.</param>
        /// <param name="error">The <see cref="Exception"/> thrown if the save was unsuccessful; otherwise <value>null</value>.</param>
        public override void PostSave(Saga saga, SagaContext context, Exception error)
        {
            if (!context.TimeoutChanged || saga == null || error != null)
            {
                return;
            }

            if (saga.Timeout.HasValue && !saga.Completed)
            {
                var timeout = saga.Timeout.Value;

                TimeoutCache.ScheduleTimeout(new SagaTimeout(saga.GetType(), saga.CorrelationId, timeout));
            }
            else
            {
                TimeoutCache.ClearTimeout(new SagaReference(saga.GetType(), saga.CorrelationId));
            }

            RescheduleTimer(TimeoutCache.GetNextScheduledTimeout());
        }
예제 #8
0
        /// <summary>
        /// Handles the <paramref name="saga"/> event.
        /// </summary>
        /// <param name="saga">The saga instance handling the event.</param>
        /// <param name="e">The event to be handled.</param>
        protected override void HandleSagaEvent(Saga saga, Event e)
        {
            var timeout = ((Timeout)e).Scheduled;

            if (saga.Timeout.HasValue)
            {
                if (saga.Timeout.Value == timeout)
                {
                    saga.ClearTimeout();
                    base.HandleSagaEvent(saga, e);
                }
                else
                {
                    Log.Warn("{0} received unexpected timeout at {1} when scheduled timeout is for {2}", saga, timeout.ToString(DateTimeFormat.RoundTrip), saga.Timeout.Value.ToString(DateTimeFormat.RoundTrip));
                }
            }
            else
            {
                Log.Warn("{0} received unexpected timeout at {1} when no timeout is scheduled", saga, timeout.ToString(DateTimeFormat.RoundTrip));
            }
        }
예제 #9
0
        /// <summary>
        /// Attempt to retrieve an existing saga instance identified by the specified <paramref name="type"/> and <paramref name="id"/>.
        /// </summary>
        /// <param name="type">The type of saga to be retrieved.</param>
        /// <param name="id">The correlation id of the saga to be retrieved.</param>
        /// <param name="saga">The <see cref="Saga"/> instance if found; otherwise <value>null</value>.</param>
        public Boolean TryGetSaga(Type type, Guid id, out Saga saga)
        {
            Verify.NotNull(type, nameof(type));

            var key = String.Concat(type.GetFullNameWithAssembly(), "-", id);

            using (var sagaLock = new SagaLock(type, id))
            {
                sagaLock.Aquire();

                //NOTE: We do not want to cache a NULL saga reference, thus explicitly check for existance and add to cache if instance found.
                saga = (Saga)memoryCache.Get(key);
                if (saga == null && sagaStore.TryGetSaga(type, id, out saga))
                {
                    memoryCache.Add(key, saga, CreateCacheItemPolicy());
                }
            }

            //NOTE: Given that saga state is modified during `Handling`, we must always return a copy of the cached instance.
            return((saga == null ? null : saga = saga.Copy()) != null);
        }
        /// <summary>
        /// Handles the <paramref name="saga"/> event.
        /// </summary>
        /// <param name="saga">The saga instance handling the event.</param>
        /// <param name="e">The event to be handled.</param>
        protected override void HandleSagaEvent(Saga saga, Event e)
        {
            var timeout = ((Timeout)e).Scheduled;

            if (saga.Timeout.HasValue)
            {
                if (saga.Timeout.Value == timeout)
                {
                    saga.ClearTimeout();
                    base.HandleSagaEvent(saga, e);
                }
                else
                {
                    Log.Warn("{0} received unexpected timeout at {1} when scheduled timeout is for {2}", saga, timeout.ToString(DateTimeFormat.RoundTrip), saga.Timeout.Value.ToString(DateTimeFormat.RoundTrip));
                }
            }
            else
            {
                Log.Warn("{0} received unexpected timeout at {1} when no timeout is scheduled", saga, timeout.ToString(DateTimeFormat.RoundTrip));
            }
        }
        /// <summary>
        /// Attempt to retrieve an existing saga instance identified by the specified <paramref name="type"/> and <paramref name="id"/>.
        /// </summary>
        /// <param name="type">The type of saga to be retrieved.</param>
        /// <param name="id">The correlation id of the saga to be retrieved.</param>
        /// <param name="saga">The <see cref="Saga"/> instance if found; otherwise <value>null</value>.</param>
        public Boolean TryGetSaga(Type type, Guid id, out Saga saga)
        {
            Verify.NotNull(type, nameof(type));

            var key = String.Concat(type.GetFullNameWithAssembly(), "-", id);
            using (var sagaLock = new SagaLock(type, id))
            {
                sagaLock.Aquire();

                //NOTE: We do not want to cache a NULL saga reference, thus explicitly check for existance and add to cache if instance found.
                saga = (Saga)memoryCache.Get(key);
                if (saga == null && sagaStore.TryGetSaga(type, id, out saga))
                    memoryCache.Add(key, saga, CreateCacheItemPolicy());
            }

            //NOTE: Given that saga state is modified during `Handling`, we must always return a copy of the cached instance.
            return (saga == null ? null : saga = saga.Copy()) != null;
        }
        /// <summary>
        /// Save the specified <paramref name="context"/> changes for the given <paramref name="saga"/>.
        /// </summary>
        /// <param name="saga">The current saga version for which the context applies.</param>
        /// <param name="context">The saga context containing the saga changes to be applied.</param>
        public Saga Save(Saga saga, SagaContext context)
        {
            Verify.NotNull(saga, nameof(saga));
            Verify.NotNull(context, nameof(context));

            var sagaType = saga.GetType();
            var key = String.Concat(sagaType.GetFullNameWithAssembly(), "-", saga.CorrelationId);
            using (var sagaLock = new SagaLock(sagaType, saga.CorrelationId))
            {
                sagaLock.Aquire();

                try
                {
                    sagaStore.Save(saga, context);

                    if (saga.Completed)
                        memoryCache.Remove(key);
                    else
                        memoryCache.Set(key, saga, CreateCacheItemPolicy());

                    return saga;
                }
                catch (ConcurrencyException)
                {
                    memoryCache.Remove(key);
                    throw;
                }
            }
        }
예제 #13
0
        /// <summary>
        /// Handles the <paramref name="saga"/> event.
        /// </summary>
        /// <param name="saga">The saga instance handling the event.</param>
        /// <param name="e">The event to be handled.</param>
        protected virtual void HandleSagaEvent(Saga saga, Event e)
        {
            Log.Trace("{0} handling event {1}", saga, e);

            Executor(saga, e);
        }
 /// <summary>
 /// Invokes zero or more customized <see cref="PipelineHook.PostSave"/> implementations.
 /// </summary>
 /// <param name="saga">The modified <see cref="Saga"/> instance if <paramref name="error"/> is <value>null</value>; otherwise the original <see cref="Saga"/> instance if <paramref name="error"/> is not <value>null</value>.</param>
 /// <param name="context">The current <see cref="SagaContext"/> assocaited with the pending saga modifications.</param>
 /// <param name="error">The <see cref="Exception"/> thrown if the save was unsuccessful; otherwise <value>null</value>.</param>
 private void InvokePostSaveHooks(Saga saga, SagaContext context, Exception error)
 {
     foreach (var pipelineHook in postSaveHooks)
     {
         Log.Trace("Invoking post-save pipeline hook: {0}", pipelineHook);
         pipelineHook.PostSave(saga, context, error);
     }
 }
 /// <summary>
 /// Invokes zero or more customized <see cref="PipelineHook.PreSave"/> implementations.
 /// </summary>
 /// <param name="saga">The saga to be modified by the current <paramref name="context"/>.</param>
 /// <param name="context">The current <see cref="SagaContext"/> associated with the pending saga modifications.</param>
 private void InvokePreSaveHooks(Saga saga, SagaContext context)
 {
     foreach (var pipelineHook in preSaveHooks)
     {
         Log.Trace("Invoking pre-save pipeline hook: {0}", pipelineHook);
         pipelineHook.PreSave(saga, context);
     }
 }
        /// <summary>
        /// Attempt to retrieve an existing saga instance identified by the specified <paramref name="type"/> and <paramref name="id"/>.
        /// </summary>
        /// <param name="type">The type of saga to be retrieved.</param>
        /// <param name="id">The correlation id of the saga to be retrieved.</param>
        /// <param name="saga">The <see cref="Saga"/> instance if found; otherwise <value>null</value>.</param>
        public Boolean TryGetSaga(Type type, Guid id, out Saga saga)
        {
            Boolean result;

            InvokePreGetHooks(type, id);

            result = sagaStore.TryGetSaga(type, id, out saga);

            InvokePostGetHooks(saga);

            return result;
        }
        /// <summary>
        /// Attempt to retrieve an existing saga instance identified by the specified <paramref name="type"/> and <paramref name="id"/>.
        /// </summary>
        /// <param name="type">The type of saga to be retrieved.</param>
        /// <param name="id">The correlation id of the saga to be retrieved.</param>
        /// <param name="saga">The <see cref="Saga"/> instance if found; otherwise <value>null</value>.</param>
        public Boolean TryGetSaga(Type type, Guid id, out Saga saga)
        {
            var result = sagaStore.TryGetSaga(type, id, out saga);

            statistics.IncrementQueryCount();

            return result;
        }
예제 #18
0
 /// <summary>
 /// When overriden, defines the custom behavior to be invoked prior to saving the specified <paramref name="saga"/>.
 /// </summary>
 /// <param name="saga">The saga to be modified using the current <paramref name="context"/>.</param>
 /// <param name="context">The current <see cref="SagaContext"/> assocaited with the pending saga modifications.</param>
 public virtual void PreSave(Saga saga, SagaContext context)
 {
 }
        /// <summary>
        /// Save the specified <paramref name="context"/> changes for the given <paramref name="saga"/>.
        /// </summary>
        /// <param name="saga">The current saga version for which the context applies.</param>
        /// <param name="context">The saga context containing the saga changes to be applied.</param>
        public Saga Save(Saga saga, SagaContext context)
        {
            InvokePreSaveHooks(saga, context);

            try
            {
                var result = sagaStore.Save(saga, context);

                InvokePostSaveHooks(result, context, null);

                return result;
            }
            catch (Exception ex)
            {
                InvokePostSaveHooks(saga, context, ex);
                throw;
            }
        }
        /// <summary>
        /// Handles the <paramref name="saga"/> event.
        /// </summary>
        /// <param name="saga">The saga instance handling the event.</param>
        /// <param name="e">The event to be handled.</param>
        protected virtual void HandleSagaEvent(Saga saga, Event e)
        {
            Log.Trace("{0} handling event {1}", saga, e);

            Executor(saga, e);
        }
예제 #21
0
 /// <summary>
 /// When overriden, defines the custom behavior to be invokes after successfully retrieving the specified <paramref name="saga"/>.
 /// </summary>
 /// <param name="saga">The loaded saga instance.</param>
 public virtual void PostGet(Saga saga)
 {
 }
        /// <summary>
        /// Save the specified <paramref name="context"/> changes for the given <paramref name="saga"/>.
        /// </summary>
        /// <param name="saga">The current saga version for which the context applies.</param>
        /// <param name="context">The saga context containing the saga changes to be applied.</param>
        public Saga Save(Saga saga, SagaContext context)
        {
            var result = sagaStore.Save(saga, context);

            if (saga.Version == 1)
            {
                statistics.IncrementInsertCount();
            }
            else
            {
                if (saga.Completed)
                {
                    statistics.IncrementDeleteCount();
                }
                else
                {
                    statistics.IncrementUpdateCount();
                }
            }

            return result;
        }
예제 #23
0
 /// <summary>
 /// When overriden, defines the custom behavior to be invokes after successfully retrieving the specified <paramref name="saga"/>.
 /// </summary>
 /// <param name="saga">The loaded saga instance.</param>
 public virtual void PostGet(Saga saga)
 {
 }
 /// <summary>
 /// Invokes zero or more customized <see cref="PipelineHook.PostGet"/> implementations.
 /// </summary>
 /// <param name="saga">The loaded saga instance.</param>
 private void InvokePostGetHooks(Saga saga)
 {
     foreach (var pipelineHook in postGetHooks)
     {
         Log.Trace("Invoking post-get pipeline hook: {0}", pipelineHook);
         pipelineHook.PostGet(saga);
     }
 }
예제 #25
0
 /// <summary>
 ///  When overriden, defines the custom behavior to be invoked after attempting to save the specified <paramref name="saga"/>.
 /// </summary>
 /// <param name="saga">The modified <see cref="Saga"/> instance if <paramref name="error"/> is <value>null</value>; otherwise the original <see cref="Saga"/> instance if <paramref name="error"/> is not <value>null</value>.</param>
 /// <param name="context">The current <see cref="SagaContext"/> assocaited with the pending saga modifications.</param>
 /// <param name="error">The <see cref="Exception"/> thrown if the save was unsuccessful; otherwise <value>null</value>.</param>
 public virtual void PostSave(Saga saga, SagaContext context, Exception error)
 {
 }
예제 #26
0
 /// <summary>
 ///  When overriden, defines the custom behavior to be invoked after attempting to save the specified <paramref name="saga"/>.
 /// </summary>
 /// <param name="saga">The modified <see cref="Saga"/> instance if <paramref name="error"/> is <value>null</value>; otherwise the original <see cref="Saga"/> instance if <paramref name="error"/> is not <value>null</value>.</param>
 /// <param name="context">The current <see cref="SagaContext"/> assocaited with the pending saga modifications.</param>
 /// <param name="error">The <see cref="Exception"/> thrown if the save was unsuccessful; otherwise <value>null</value>.</param>
 public virtual void PostSave(Saga saga, SagaContext context, Exception error)
 {
 }
        /// <summary>
        ///  When overriden, defines the custom behavior to be invoked after attempting to save the specified <paramref name="saga"/>.
        /// </summary>
        /// <param name="saga">The modified <see cref="Saga"/> instance if <paramref name="error"/> is <value>null</value>; otherwise the original <see cref="Saga"/> instance if <paramref name="error"/> is not <value>null</value>.</param>
        /// <param name="context">The current <see cref="SagaContext"/> assocaited with the pending saga modifications.</param>
        /// <param name="error">The <see cref="Exception"/> thrown if the save was unsuccessful; otherwise <value>null</value>.</param>
        public override void PostSave(Saga saga, SagaContext context, Exception error)
        {
            if (!context.TimeoutChanged || saga == null || error != null)
                return;

            if (saga.Timeout.HasValue && !saga.Completed)
            {
                var timeout = saga.Timeout.Value;

                TimeoutCache.ScheduleTimeout(new SagaTimeout(saga.GetType(), saga.CorrelationId, timeout));
            }
            else
            {
                TimeoutCache.ClearTimeout(new SagaReference(saga.GetType(), saga.CorrelationId));
            }

            RescheduleTimer(TimeoutCache.GetNextScheduledTimeout());
        }
예제 #28
0
 /// <summary>
 /// When overriden, defines the custom behavior to be invoked prior to saving the specified <paramref name="saga"/>.
 /// </summary>
 /// <param name="saga">The saga to be modified using the current <paramref name="context"/>.</param>
 /// <param name="context">The current <see cref="SagaContext"/> assocaited with the pending saga modifications.</param>
 public virtual void PreSave(Saga saga, SagaContext context)
 {
 }