Esempio n. 1
0
        private static void Rollback(EventLog log, EventLogEntry logEntry, Exception reason)
        {
            var queueId = log.Id;

            if (logEntry.Operation == EventOperation.Raise)
            {
                var content = DTObject.CreateReusable(logEntry.ContentCode);
                var entryId = content.GetValue <int>("entryId");

                var queue = EventQueue.Find(queueId);
                if (queue.IsEmpty())
                {
                    return;
                }
                var entry = queue.GetEntry(entryId);
                if (!entry.IsEmpty())
                {
                    Reverse(queue, entry);
                }
                EventQueue.Update(queue);
            }
            else if (logEntry.Operation == EventOperation.Start)
            {
                EventQueue.Delete(queueId);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// 执行远程事件超时
        /// </summary>
        /// <param name="queueId"></param>
        /// <param name="key"></param>
        /// <param name="callback"></param>
        public static void Timeout(Guid queueId, EventKey key, EventCallback callback)
        {
            TimeoutManager.End(key);
            //首先释放资源,删除为了收取信息而建立的临时队列
            CleanupRemoteEventResult(key.EventName, key.EventId);

            //记录异常状态
            DataContext.NewScope(() =>
            {
                var queue = EventQueue.Find(queueId);
                if (queue.IsEmpty())
                {
                    return;
                }

                var entry = queue.GetEntry(key.EventId);
                if (entry.IsEmpty() || entry.IsLocal)
                {
                    return;
                }

                entry.Status = EventStatus.TimedOut;

                EventQueue.Update(queue);
            }, true);

            //抛出执行失败的异常
            throw new RemoteEventFailedException(Strings.ExecuteRemoteEventTimeout);
        }
Esempio n. 3
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);
        }
Esempio n. 4
0
        /// <summary>
        /// 完成远程事件
        /// </summary>
        /// <param name="event"></param>
        private static void CompleteRemoteEvent(Guid queueId, DTObject @event, EventKey key)
        {
            if (!TimeoutManager.End(key))
            {
                return;                           //如果结束失败,证明已超时了
            }
            //首先释放资源,删除为了收取信息而建立的临时队列
            CleanupRemoteEventResult(key.EventName, key.EventId);

            //再处理结果
            var success = @event.GetValue <bool>("success");
            var message = @event.GetValue <string>("message");

            if (!success)
            {
                //如果没有执行成功,那么抛出异常
                throw new RemoteEventFailedException(message);
            }

            var args = @event.GetObject("args");

            DataContext.NewScope(() =>
            {
                var queue = EventQueue.Find(queueId);
                if (queue.IsEmpty())
                {
                    //短期内事件队列不存在只有一个原因,那就是由于回逆而被删除了
                    //长期内事件不存在,那是因为为防止数据过多导致性能下降,已完成的过期队列会被删除,这种情况下不可能被继续调用,不会执行到这里来
                    throw new DomainEventException(string.Format(Strings.QueueNotExistWithCallbackTip, queue.Id));
                }

                var entry = queue.GetEntry(key.EventId);
                if (entry.IsEmpty())
                {
                    throw new DomainEventException(string.Format(Strings.EventEntryNotExistWithCallbackTip, queue.Id, entry.EventId));
                }

                if (entry.IsLocal) //本地事件是不能继续触发的,这明显是个致命错误
                {
                    throw new DomainEventException(string.Format(Strings.ContinueNotWithLocal, entry.EventName));
                }

                if (entry.Status == EventStatus.TimedOut) //已经超时了,抛出异常
                {
                    throw new RemoteEventFailedException(Strings.ExecuteRemoteEventTimeout);
                }

                //远程事件执行完毕后,用它所在的源事件接受结果
                var source = entry.GetSourceEvent();
                source.ApplyResult(entry.EventName, args);

                entry.Status = EventStatus.Raised;

                EventQueue.Update(queue);
            }, true);
        }
Esempio n. 5
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);
        }
Esempio n. 6
0
        /// <summary>
        /// 触发队列事件
        /// </summary>
        /// <param name="queue"></param>
        private static void Raise(Guid queueId, EventCallback callback)
        {
            bool isSucceeded = false;
            bool isRunning   = false;

            while (!isRunning && !isSucceeded)
            {
                DataContext.NewScope(() =>
                {
                    //触发队列事件
                    var queue = EventQueue.Find(queueId);
                    var entry = queue.GetPreRaise();
                    if (!entry.IsEmpty())
                    {
                        var args = entry.GetArgs(); //获取条目的事件参数
                        EventLog.FlushRaise(queue, entry);
                        if (entry.IsLocal)
                        {
                            var source = entry.GetSourceEvent();
                            var local  = EventFactory.GetLocalEvent(entry, args, true);
                            RaiseLocalEvent(entry, local, source);
                        }
                        else
                        {
                            var identity = queue.GetIdentity();
                            RaiseRemoteEvent(entry, identity, args);
                        }
                    }
                    EventQueue.Update(queue);
                    isRunning   = queue.IsRunning;
                    isSucceeded = queue.IsSucceeded;
                }, true);
            }

            bool        completed = false;
            DomainEvent @event    = null;

            if (isSucceeded)
            {
                DataContext.NewScope(() =>
                {
                    var queue = EventQueue.Find(queueId);
                    if (queue.IsSubqueue)
                    {
                        var entry    = queue.Source;
                        var argsCode = entry.ArgsCode;

                        var identity  = queue.GetIdentity();
                        var eventName = entry.EventName;
                        var eventId   = entry.EventId;
                        callback.Mount(() => //挂载回调事件,这样所有操作执行完毕后,会发布事件被完成的消息
                        {
                            //发布事件被完成的消息
                            PublishRaiseSucceeded(identity, eventName, eventId, argsCode);
                        });
                    }
                    else
                    {
                        //不是被外界调用的,所以整个事件场景已完成
                        completed = true;
                        @event    = queue.Source.GetSourceEvent();
                    }
                }, true);
                EventLog.FlushEnd(queueId); //指示恢复管理器事件队列的操作已经全部完成
            }

            if (completed)
            {
                callback.Mount(() => //挂载回调事件
                {
                    DomainEvent.OnSucceeded(queueId, @event);
                });
            }
        }