Example #1
0
        /// <summary>
        /// 移除超过24小时已完成的事件锁、事件监视器、队列信息
        /// 我们不能在执行完领域事件后立即删除这些信息,因为有可能是外界调用本地的事件,稍后可能外界要求回逆事件
        /// 因此我们只删除24小时过期的信息,因为外界不可能过了24小时后又要求回逆
        /// </summary>
        /// <param name="minutes"></param>
        private static void Clear()
        {
            DataContext.NewScope(() =>
            {
                var repository = Repository.Create <IEventLockRepository>();
                var locks      = repository.FindExpireds(24);
                foreach (var @lock in locks)
                {
                    var queueId = @lock.Id;

                    var queue = EventQueue.Find(queueId);
                    if (!queue.IsSucceeded)
                    {
                        continue;                     //对于没有执行成功的队列,我们不删除日志等信息,这样管理员可以排查错误
                    }
                    DataContext.NewScope(() =>
                    {
                        var monitor = EventMonitor.Find(queueId);
                        if (!monitor.IsEmpty())
                        {
                            EventMonitor.Delete(monitor);
                        }

                        EventQueue.Delete(queueId);
                        EventLogEntry.Deletes(queueId); //删除日志的所有条目
                        EventLog.Delete(queueId);
                    }, true);
                    EventLock.Delete(@lock);
                }
            }, true);
        }
Example #2
0
        /// <summary>
        /// 有两种情况会恢复:
        /// 1.调用方主动要求恢复(这一般是因为调用方出了错误,要求被调用的领域事件恢复),这时候本地的事件队列就算是成功执行完毕的(非中断),也需要恢复
        /// 2.本地机器故障或业务错误,要求恢复
        /// </summary>
        /// <param name="queueId"></param>
        /// <param name="reason"></param>
        /// <param name="forceRestore">即使监视器不会中断的,也要回逆,这一般是因为调用方发布的回逆要求</param>
        /// <returns></returns>
        public static bool TryRestore(Guid queueId, Exception reason, bool forceRestore)
        {
            bool success = false; //是否成功恢复

            try
            {
                DataContext.NewScope(() =>
                {
                    var @lock = EventLock.Find(queueId, QueryLevel.Single);//这段代码将入口锁住,所以监视器和队列也间接被锁住了
                    if (@lock.IsEmpty())
                    {
                        return;                  //没有锁,那么意味着队列及相关的数据已被恢复了
                    }
                    var monitor = EventMonitor.Find(queueId);

                    var queue = EventQueue.Find(queueId);
                    if (queue.IsEmpty())
                    {
                        //队列不存在,要么是队列已被恢复了,要么就是队列还没初始化之前,就被终止了
                        //删除监视器
                        if (!monitor.IsEmpty())
                        {
                            EventMonitor.Delete(monitor);
                        }
                        //删除锁
                        EventLock.Delete(@lock);
                        success = true;
                        return;
                    }


                    if (!forceRestore && !monitor.Interrupted)
                    {
                        //由于中断的监视器有可能是正在运行中的(正在执行的队列我们会把监视器设置为中断,当队列执行完毕后恢复为非中断),所以这类监视器运行完毕后,就不再中断了
                        //所以就不需要恢复
                        success = false;
                        return;
                    }

                    //防止恢复过程中也断电或故障,这里主动设置为中断的
                    monitor.Interrupted = true;
                    EventMonitor.UpdateAndFlush(monitor);

                    Restore(queueId, reason);

                    //恢复完毕后,删除监视器
                    EventMonitor.Delete(monitor);
                    //删除锁
                    EventLock.Delete(@lock);
                }, true);

                DomainEvent.OnFailed(queueId, new EventFailedException(reason));
                success = true;
            }
            catch (EventRestoreException)
            {
                //Restore方法已写入日志,就不再写入
                DomainEvent.OnError(queueId, new EventErrorException(reason));
                throw;
            }
            catch (Exception ex)
            {
                LogWrapper.Default.Fatal(ex);
            }
            return(success);
        }
Example #3
0
        /// <summary>
        /// 使用队列
        /// </summary>
        /// <param name="queueId">队列编号</param>
        /// <param name="newQueue">是否新建队列</param>
        /// <param name="action">使用队列完成的任务</param>
        /// <param name="error">发生错误时的回调</param>
        public static void UseQueue(Guid queueId, bool newQueue, Action <EventCallback> action, Action <Exception> error = null)
        {
            EventCallback callBack  = new EventCallback();
            Exception     exception = null;

            try
            {
                DataContext.NewScope(() =>
                {
                    var @lock = newQueue ? EventLock.GetOrCreate(queueId)
                                      : EventLock.Find(queueId, QueryLevel.Single);//这段代码将入口锁住,所以监视器和队列也间接被锁住了

                    if (@lock.IsEmpty())
                    {
                        return;                  //无相关的信息,直接返回(保证幂等性,有可能队列被多次重复处理)
                    }
                    var monitor = newQueue ? EventMonitor.GetOrCreate(queueId)
                                         : EventMonitor.Find(queueId);

                    if (monitor.IsEmpty())
                    {
                        return;
                    }
                    if (monitor.Interrupted)
                    {
                        return;                      //监视器被中断,那么需要等待恢复,不必执行队列
                    }
                    monitor.Interrupted = true;
                    EventMonitor.UpdateAndFlush(monitor); //主动将监视器设置为中断的,这样后续的操作中如果出错或者中途断电,监视器就是中断的了,可以被恢复

                    action(callBack);

                    if (callBack.HasAction)
                    {
                        //执行注册的回调方法
                        callBack.Execute();
                    }

                    monitor.Interrupted = false;
                    EventMonitor.Update(monitor); //修改监视器为不中断的,但是此处不提交,而是跟整体操作一起提交才生效
                }, true);
            }
            catch (Exception ex)
            {
                exception = ex;
            }

            if (exception != null)
            {
                try
                {
                    LogWrapper.Default.Fatal(exception);
                    //自定义错误处理
                    if (error != null)
                    {
                        error(exception);
                    }
                }
                catch (Exception ex)
                {
                    //如果自定义错误处理也出错,那么写入日志
                    LogWrapper.Default.Fatal(ex);
                }

                //恢复
                TryRestore(queueId, exception, true);
            }
        }