예제 #1
0
        public override Action consume(Message value, ConsumeContext context)
        {
            Action action = ons.Action.ReconsumeLater;

            try
            {
                //DebugUtil.Debug("MESSAGE_KEY:" + value.getKey() + ",consume...");

                bool needToCommit = ListenerHelper.React(value, this.ClassType);

                if (needToCommit)
                {
                    //DebugUtil.Debug("MESSAGE_KEY:" + value.getKey() + ",ons.Action.CommitMessage...\n");
                    action = ons.Action.CommitMessage;
                }
                else
                {
                    //DebugUtil.Debug("MESSAGE_KEY:" + value.getKey() + ",ons.Action.ReconsumeLater...\n");
                    action = ons.Action.ReconsumeLater;
                }
            }
            catch (Exception e)
            {
                DebugUtil.Debug("MESSAGE_KEY:" + value.getKey() + ",error:" + e.ToString());
            }
            return(action);
        }
예제 #2
0
        public override OrderAction consume(Message value, ConsumeOrderContext context)
        {
            OrderAction action = ons.OrderAction.Suspend;

            try
            {
                //DebugUtil.Debug("MESSAGE_KEY:" + value.getKey() + ",consume...");

                bool needToCommit = ListenerHelper.React(value, this.ClassType);

                if (needToCommit)
                {
                    //DebugUtil.Debug("MESSAGE_KEY:" + value.getKey() + ",ons.OrderAction.Success...\n");
                    action = ons.OrderAction.Success;
                }
                else
                {
                    //DebugUtil.Debug("MESSAGE_KEY:" + value.getKey() + ",ons.OrderAction.Suspend;...\n");
                    action = ons.OrderAction.Suspend;
                }
            }
            catch (Exception e)
            {
                DebugUtil.Debug("MESSAGE_KEY:" + value.getKey() + ",error:" + e.ToString());
            }

            return(action);
        }
예제 #3
0
        /// <summary>
        /// 代理OrderProducer实例的send方法
        /// </summary>
        /// <param name="message">Message实例</param>
        /// <param name="parameter">parameter参数</param>
        /// <returns>SendResultONS实例</returns>
        public SendResultONS send(Message message, object parameter)
        {
            SendResultONS sendResultONS = null;

            if (_producer != null)
            {
                string shardingKey = parameter.ToString();
                DebugUtil.Debug("shardingKey:" + shardingKey);
                sendResultONS = _producer.send(message, shardingKey);
            }
            return(sendResultONS);
        }
예제 #4
0
        /// <summary>
        /// 尝试发送消息
        /// </summary>
        /// <param name="producer">生产者实例</param>
        /// <param name="message">消息实例</param>
        /// <param name="parameter">发送所需参数</param>
        /// <param name="key">消息的唯一标识</param>
        /// <param name="errorTimes">本系统自己自己执行时发现出错后,记录的错误次数(此参数不适用于生产次数)</param>
        /// <returns></returns>
        protected SendResultONS TryToSend(IONSProducer producer, Message message, object parameter, string key, int errorTimes)
        {
            SendResultONS sendResultONS = null;

            try
            {
                sendResultONS = producer.send(message, parameter);
            }
            catch (Exception e)
            {
                //错误计数累加
                errorTimes++;
                //无论是阿里云服务不可用,还是生产者挂了,一共3次机会,即执行1次,然后最多重试两次
                if (errorTimes < 3)
                {
                    //如果生产者挂了
                    if (e.ToString().IndexOf("Your producer has been shutdown.") >= 0)
                    {
                        //置空producer
                        producer = null;
                        //重新获取producer并启动
                        producer = GetProducer();
                        //等待3秒
                        System.Threading.Thread.Sleep(3000);
                    }
                    else
                    {
                        //如果是阿里云服务不可用,等待1秒
                        System.Threading.Thread.Sleep(1000);
                    }

                    //递归
                    sendResultONS = TryToSend(producer, message, parameter, key, errorTimes);
                }
                else
                {
                    //重试2次都还是失败
                    string className    = this.GetType().Name;
                    string methodName   = "Process";
                    string errorMessage = _Environment + "." + _ApplicationAlias + "." + className + "." + methodName + "尝试发送时,出现了第" + errorTimes + "次出错,key=" + key + ":" + e.ToString();
                    //记录本地错误日志
                    DebugUtil.Debug(errorMessage);
                    //记录FATAL日志
                    ONSHelper.SaveLog(LogTypeEnum.FATAL, className, methodName, errorMessage);
                    //发送邮件
                    ONSHelper.SendDebugMail(_Environment + "." + _ApplicationAlias + "." + className + "." + methodName + "尝试发送时出错", errorMessage);
                    //抛出异常
                    throw new Exception(errorMessage);
                }
            }

            return(sendResultONS);
        }
예제 #5
0
 /// <summary>
 /// 发送DEBUG邮件,一般在发生严重FATAL错误时,需要发送邮件通知该网站相关人员
 /// </summary>
 /// <param name="subject">邮件主题</param>
 /// <param name="body">邮件内容</param>
 public static void SendDebugMail(string subject, string body)
 {
     try
     {
         string resultMessage = "";
         MailUtil.SendDebugMail(subject, body, out resultMessage);
     }
     catch (Exception mailError)
     {
         //发送邮件错误
         DebugUtil.Debug(subject + "," + body + ",尝试发送邮件时发生异常:" + mailError.ToString());
     }
 }
예제 #6
0
        /// <summary>
        /// 创建生产者实例
        /// </summary>
        /// <typeparam name="T">生产者服务基类类型</typeparam>
        /// <param name="assembly">生产者服务类所在程序集</param>
        /// <param name="type">生产者服务类的类型</param>
        /// <param name="messageType">消息类型BASE,ORDER,TRAN</param>
        /// <param name="func">生成生产者实例的委托代码</param>
        internal static void CreateProducer <T>(Assembly assembly, Type type, ONSMessageType messageType, Func <ONSFactoryProperty, string, string, IONSProducer> func)
        {
            if (type.BaseType.FullName.IndexOf(typeof(T).Name) >= 0)
            {
                //添加到生产者服务类实例列表
                //ONSProducerServiceList.Add(type);
                object service = assembly.CreateInstance(type.FullName);
                ONSProducerServiceList.Add(service);
                //获取服务接口
                IAbstractProducerService iservice = (IAbstractProducerService)service;
                //获取枚举对象
                Enum topicTag = iservice.TopicTag;

                if (topicTag != null)
                {
                    string serviceTopic = topicTag.GetType().Name;
                    string topic        = (_Environment + "_" + serviceTopic).ToUpper();
                    //string producerId = ("PID_" + topic).ToUpper();
                    string       producerId = ("GID_" + topic).ToUpper();
                    IONSProducer producer   = ONSProducerList.Where(p => (p.Type == messageType.ToString()) && (p.ProducerId == producerId)).FirstOrDefault();
                    if (producer == null)
                    {
                        //实例化ONSFactoryProperty
                        ONSFactoryProperty onsProducerFactoryProperty = new ONSFactoryProperty();
                        onsProducerFactoryProperty.setFactoryProperty(ONSFactoryProperty.AccessKey, _AliyunOnsAccessKey);
                        onsProducerFactoryProperty.setFactoryProperty(ONSFactoryProperty.SecretKey, _AliyunOnsSecretKey);
                        //用老的.net SDK按最新的RocketMQ架构,引入GroupId代替ProducerId和ConsumerId
                        onsProducerFactoryProperty.setFactoryProperty(ONSFactoryProperty.ProducerId, producerId);
                        onsProducerFactoryProperty.setFactoryProperty(ONSFactoryProperty.PublishTopics, topic);

                        if (_AliyunOnsProducerLogPath != "")
                        {
                            if (Directory.Exists(_AliyunOnsProducerLogPath))
                            {
                                onsProducerFactoryProperty.setFactoryProperty(ONSFactoryProperty.LogPath, _AliyunOnsProducerLogPath);
                            }
                        }

                        //获取生产者IONSProducer
                        producer = func(onsProducerFactoryProperty, topic, producerId);

                        //记录生产者初始化信息
                        DebugUtil.Debug("Topic:" + topic + ",ProducerId(" + producer.Type.ToString() + "):" + producer.ProducerId + "生产者new()");

                        //新增代理类ONSProducer实例到ONSProducerList中
                        ONSProducerList.Add(producer);
                    }
                }
            }
        }
예제 #7
0
 /// <summary>
 /// 记录日志(建议在有上下文的环境下使用,否则可能会报错)
 /// </summary>
 /// <param name="logType">日志类型TRACE,INFO,ERROR,FATAL</param>
 /// <param name="className">哪个类中出错</param>
 /// <param name="methodName">哪个方法中出错</param>
 /// <param name="content">日志内容</param>
 public static void SaveLog(LogTypeEnum logType, string className, string methodName, string content)
 {
     try
     {
         LogParameter logParameter = new LogParameter();
         logParameter.LogType    = logType;
         logParameter.ClassName  = className;
         logParameter.MethodName = methodName;
         logParameter.LogMessage = content;
         NestLogHelper.WriteLog(logParameter);
     }
     catch (Exception esError)
     {
         //发送es日志异常
         DebugUtil.Debug(content + ",尝试发送es的FATAL日志时发生异常:" + esError.ToString());
     }
 }
예제 #8
0
        /// <summary>
        /// 销毁ONS事务消息相关对象,一般在Application_End中调用
        /// </summary>
        public static void Destroy()
        {
            if (_AliyunOnsIsEnabled == "1")
            {
                try
                {
                    if (ONSProducerList != null && ONSProducerList.Count > 0)
                    {
                        ONSProducerList.ForEach(producer =>
                        {
                            //关闭上游消息生产者
                            DebugUtil.Debug("ProducerId(" + producer.Type.ToString() + @"):" + producer.ProducerId + @"生产者.准备shutdown()");
                            producer.shutdown();
                            DebugUtil.Debug("ProducerId(" + producer.Type.ToString() + @"):" + producer.ProducerId + @"生产者.shutdown()");
                        });
                    }

                    if (ONSConsumerList != null && ONSConsumerList.Count > 0)
                    {
                        ONSConsumerList.ForEach(consumer =>
                        {
                            //关闭下游消息消费者
                            DebugUtil.Debug("ConsumerId(" + consumer.Type.ToString() + @"):" + consumer.ConsumerId + @"消费者.准备shutdown()");
                            consumer.shutdown();
                            DebugUtil.Debug("ConsumerId(" + consumer.Type.ToString() + @"):" + consumer.ConsumerId + @"消费者.shutdown()");
                        });
                    }

                    //延时若干毫秒
                    Thread.Sleep(1000);
                    DebugUtil.Debug(_Environment + "." + _ApplicationAlias + ".ONSHelper.Destroy最后延迟1000毫秒");
                }
                catch (Exception e)
                {
                    //记录本地错误日志
                    DebugUtil.Debug(_Environment + "." + _ApplicationAlias + ".ONSHelper.Destroy出错:" + e.ToString());

                    //记录FATAL日志,发送FATAL目前出错
                    //SaveLog(LogTypeEnum.FATAL, "ONSHelper", "Destroy", _Environment + "." + _ApplicationAlias + ".ONSHelper.Destroy出错:" + e.ToString());

                    //发送邮件
                    SendDebugMail(_Environment + "." + _ApplicationAlias + ".ONSHelper.Destroy出错", ":" + e.ToString());
                }
            }
        }
예제 #9
0
        public static bool React(Message value, Type classType)
        {
            bool   needToCommit   = false;
            string failureReason  = "";
            string topic          = "";
            string tag            = "";
            string pid            = "";
            string cid            = "";
            string key            = "";
            string type           = "";
            string body           = "";
            string method         = "";
            string requestTraceId = "";
            string shardingKey    = "";
            Enum   topicTag       = null;
            int    consumedTimes  = 0;

            //尝试找到消费者服务类实例来消费
            try
            {
                topic = value.getTopic();
                tag   = value.getTag();
                //pid = "PID_" + value.getTopic().ToUpper();
                pid = "GID_" + value.getTopic().ToUpper();
                //cid = ("CID_" + topic + "_" + _ApplicationAlias + "_" + classType.Name).ToUpper();
                cid            = ("GID_" + topic + "_" + _ApplicationAlias + "_" + classType.Name).ToUpper();
                key            = value.getKey();
                type           = value.getUserProperties("type");
                body           = value.getMsgBody();
                body           = Base64Util.Decode(body);
                requestTraceId = value.getUserProperties("requestTraceId") ?? "";
                shardingKey    = value.getUserProperties("shardingKey") ?? "";

                //由于CallContext中不存在TraceId,则直接添加,以便在非http请求环境下获取到TraceId
                CallContext.LogicalSetData("TraceId", requestTraceId);

                object parameter;

                RedisTool RT = new RedisTool(_AliyunOnsRedisDbNumber, _RedisExchangeHosts);
                if (RT != null)
                {
                    string   antirepeatKey = key + "_" + cid + "_antirepeat";
                    DateTime dateTime      = DateTime.Now;
                    TimeSpan timeSpan      = dateTime.AddSeconds(1) - dateTime;
                    bool     setResult     = RT.StringSet(antirepeatKey, "1", timeSpan, When.NotExists);
                    if (!setResult)
                    {
                        //如果设置失败,则说明key已经存在,本消息属于重复消费,直接返回true,不执行后面的消费逻辑
                        return(true);
                    }

                    /*
                     * //在ONSConsumerServiceList中找到能匹配TopicTag的消费者服务类实例
                     * object service = ONSHelper.ONSConsumerServiceList.Where(s =>
                     * {
                     *  string className = s.GetType().Name;
                     *  IAbstractConsumerService iservice = (IAbstractConsumerService)s;
                     *  Enum[] topicTagList = iservice.TopicTagList;
                     *  if (topicTagList != null)
                     *  {
                     *      //需要同时判断topic和tag都匹配
                     *      topicTag = topicTagList.Where(tt =>
                     *      {
                     *          string serviceTopic = (_Environment + "_" + tt.GetType().Name).ToUpper();
                     *          string serviceTag = tt.ToString();
                     *          return (topic.ToUpper() == serviceTopic) && (tag.ToUpper() == serviceTag.ToUpper());
                     *      }).FirstOrDefault();
                     *
                     *      if (topicTag != null)
                     *      {
                     *          return true;
                     *      }
                     *  }
                     *  return false;
                     * }).FirstOrDefault();
                     * //*/

                    object service = ONSHelper.ONSConsumerServiceList.Where(s => s.GetType().Name == classType.Name).FirstOrDefault();

                    //如果消费者服务类实例存在则消费消息
                    if (service != null)
                    {
                        //获取消费服务类的核心方法(即开发者自己实现的方法)
                        method = service.GetType().FullName + ".ProcessCore";
                        //获取内部方法(此方法是受保护的,因此获取MethodInfo复杂一些)
                        MethodInfo methodInfo = service.GetType().GetMethod("InternalProcess", BindingFlags.NonPublic | BindingFlags.Instance);
                        //获取参数列表,实际就一个泛型T参数
                        ParameterInfo[] parameterInfos = methodInfo.GetParameters();
                        //判断类型
                        if (parameterInfos[0].ParameterType.ToString().ToLower() == "system.string")
                        {
                            //string类型
                            parameter = body;
                        }
                        else
                        {
                            //自定义类型
                            parameter = JsonConvert.DeserializeObject(body, parameterInfos[0].ParameterType);
                        }
                        //执行InternalProcess方法
                        needToCommit = (bool)methodInfo.Invoke(service, new object[] { parameter });

                        if (needToCommit == false)
                        {
                            failureReason = method + "执行返回false,可能是该方法逻辑上返回false,也可能是该方法执行时它自己捕捉到错误返回false";
                        }
                    }
                    else
                    {
                        //找不到消费者实例对象
                        DebugUtil.Debug("MESSAGE_KEY:" + key + ",找不到消费者实例,topic:" + topic + ",tag:" + tag + "");
                    }
                }
                else
                {
                    failureReason = "尝试通过redis写入“key来做避免重复消费的判断”时,无法实例化redis工具类,可能是redis服务暂不可用。";
                }
            }
            catch (Exception e)
            {
                failureReason = "尝试消费时,key=" + key + ",捕获异常:" + e.ToString();
                //DebugUtil.Debug(e.ToString());
            }
            //*/

            //尝试记录消费信息
            try
            {
                //获取redis客户端工具实例
                RedisTool RT = new RedisTool(_AliyunOnsRedisDbNumber, _RedisExchangeHosts);
                if (RT != null)
                {
                    string consumedTimesKey = key + "_" + cid + "_consumedtimes";
                    //设置消费次数并自增
                    consumedTimes = (int)RT.StringIncrement(consumedTimesKey);
                    //获取过期时间
                    TimeSpan?timeSpan = RT.KeyTimeToLive(consumedTimesKey);
                    if (timeSpan == null)
                    {
                        //没设置过过期时间,则设置过期时间
                        RT.KeyExpire(consumedTimesKey, TimeSpan.FromSeconds(_AliyunOnsRedisServiceResultExpireIn));
                    }
                }
                else
                {
                    failureReason = "尝试通过redis更新生产方法执行次数时,无法实例化redis工具类,可能是redis服务暂不可用。";
                }
            }
            catch (Exception e)
            {
                failureReason = "尝试通过redis更新生产方法执行次数时,捕捉异常:" + e.ToString();
                //DebugUtil.Debug(e.ToString());
            }
            finally
            {
                try
                {
                    //写ConsumerData数据
                    ConsumerData consumerData = new ConsumerData(requestTraceId);
                    //string data;
                    consumerData.ApplicationAlias = _ApplicationAlias;
                    consumerData.Accomplishment   = needToCommit;
                    consumerData.Topic            = topic;
                    consumerData.Tag            = tag;
                    consumerData.ProducerId     = pid;
                    consumerData.ConsumerId     = cid;
                    consumerData.Key            = key;
                    consumerData.Type           = type;
                    consumerData.Message        = body;
                    consumerData.Method         = method;
                    consumerData.FailureReason  = failureReason;
                    consumerData.ConsumedStatus = needToCommit ? "Commit" : "Reconsume";
                    consumerData.ConsumedTimes  = consumedTimes;
                    consumerData.ShardingKey    = shardingKey;
                    consumerData.ServerIp       = ONSHelper.GetServerIp();
                    NestDataHelper.WriteData(consumerData);
                }
                catch (Exception e)
                {
                    ONSHelper.SendDebugMail(_Environment + "." + _ApplicationAlias + "环境发送下游消费日志失败", "消息key:" + key + ",错误信息如下:" + e.ToString());
                }
            }

            return(needToCommit);
        }
예제 #10
0
        /// <summary>
        /// 初始化ONS事务消息相关对象,一般在Application_Start中调用
        /// </summary>
        public static void Initialize()
        {
            if (_AliyunOnsIsEnabled == "1")
            {
                try
                {
                    //初始化服务类列表和服务类标签列表
                    InitializeProperties();

                    //判断生产者的服务类是否存在
                    if (ONSProducerServiceList.Count > 0)
                    {
                        //输出生产服务类类名
                        ONSProducerServiceList.ForEach(service => DebugUtil.Debug("生产者的服务类:" + service.GetType().FullName));

                        //判断生产者实例列表是否为空
                        if (ONSProducerList != null && ONSProducerList.Count > 0)
                        {
                            ONSProducerList.ForEach(producer =>
                            {
                                //启动上游事务生产者
                                producer.start();
                                DebugUtil.Debug("Topic:" + producer.Topic + ",ProducerId(" + producer.Type.ToString() + @"):" + producer.ProducerId + @"生产者.start()");
                            });
                        }
                    }

                    //判断消费者的服务类是否存在
                    if (ONSConsumerServiceList.Count > 0)
                    {
                        //输出消费服务类类名
                        ONSConsumerServiceList.ForEach(service => DebugUtil.Debug("消费者的服务类:" + service.GetType().FullName));

                        //判断消费者实例列表是否为空
                        if (ONSConsumerList != null && ONSConsumerList.Count > 0)
                        {
                            ONSConsumerList.ForEach(consumer =>
                            {
                                string tags = GetConsumerServiceTags(consumer.TagList);
                                consumer.subscribe(consumer.Topic, tags);
                                //启动上游事务生产者
                                consumer.start();
                                DebugUtil.Debug("Topic:" + consumer.Topic + ",ConsumerId(" + consumer.Type.ToString() + @"):" + consumer.ConsumerId + @"消费者.start(),topic:" + consumer.Topic + ",tags:" + tags);
                            });
                        }
                    }

                    //延时若干毫秒
                    Thread.Sleep(1000);
                    DebugUtil.Debug(_Environment + "." + _ApplicationAlias + ".ONSHelper.Initialize最后延迟1000毫秒");
                }
                catch (Exception e)
                {
                    //记录本地错误日志
                    DebugUtil.Debug(_Environment + "." + _ApplicationAlias + ".ONSHelper.Initialize出错:" + e.ToString());

                    //记录FATAL日志,发送FATAL目前出错
                    //SaveLog(LogTypeEnum.FATAL, "ONSHelper", "Initialize", _Environment + "." + _ApplicationAlias + ".ONSHelper.Initialize出错:" + e.ToString());

                    //发送邮件
                    SendDebugMail(_Environment + "." + _ApplicationAlias + ".ONSHelper.Initialize出错", ":" + e.ToString());
                }
            }
        }
예제 #11
0
        /// <summary>
        /// 生成消费者实例
        /// </summary>
        /// <typeparam name="T">消费者服务基类类型</typeparam>
        /// <param name="assembly">消费者服务类所在程序集</param>
        /// <param name="type">消费者服务类的类型</param>
        /// <param name="messageType">消息类型BASE,ORDER,TRAN</param>
        /// <param name="func">生成消费者实例的委托代码</param>
        internal static void CreateConsumer <T>(Assembly assembly, Type type, ONSMessageType messageType, Func <ONSFactoryProperty, string, string, Type, IONSConsumer> func)
        {
            if (type.BaseType.FullName.IndexOf(typeof(T).Name) >= 0)
            {
                //添加到消费者服务类实例列表
                //ONSConsumerServiceList.Add(type);
                object service = assembly.CreateInstance(type.FullName);
                ONSConsumerServiceList.Add(service);
                //获取服务接口
                IAbstractConsumerService iservice = (IAbstractConsumerService)service;
                //获取枚举数组对象
                Enum[] topicTagList = iservice.TopicTagList;

                if (topicTagList != null && topicTagList.Length > 0)
                {
                    foreach (Enum topicTag in topicTagList)
                    {
                        string serviceTopic = topicTag.GetType().Name;
                        string serviceTag   = topicTag.ToString();
                        string className    = type.Name;

                        string topic      = (_Environment + "_" + serviceTopic).ToUpper();
                        string consumerId = ("CID_" + topic + "_" + _ApplicationAlias + "_" + className).ToUpper();

                        DebugUtil.Debug("consumerId:" + consumerId);

                        IONSConsumer consumer = ONSConsumerList.Where(c => c.Type == messageType.ToString() && c.ConsumerId == consumerId).FirstOrDefault();
                        if (consumer == null)
                        {
                            //实例化ONSFactoryProperty
                            ONSFactoryProperty onsConsumerFactoryProperty = new ONSFactoryProperty();
                            onsConsumerFactoryProperty.setFactoryProperty(ONSFactoryProperty.AccessKey, _AliyunOnsAccessKey);
                            onsConsumerFactoryProperty.setFactoryProperty(ONSFactoryProperty.SecretKey, _AliyunOnsSecretKey);
                            onsConsumerFactoryProperty.setFactoryProperty(ONSFactoryProperty.ConsumerId, consumerId);
                            //onsConsumerFactoryProperty.setFactoryProperty(ONSFactoryProperty.PublishTopics, _ONSTopic);

                            if (_AliyunOnsConsumerLogPath != "")
                            {
                                if (Directory.Exists(_AliyunOnsConsumerLogPath))
                                {
                                    onsConsumerFactoryProperty.setFactoryProperty(ONSFactoryProperty.LogPath, _AliyunOnsConsumerLogPath);
                                }
                            }

                            //获取消费者IONSConsumer
                            consumer = func(onsConsumerFactoryProperty, topic, consumerId, type);

                            //记录消费者初始化信息
                            DebugUtil.Debug("Topic:" + topic + ",ConsumerId(" + consumer.Type + "):" + consumer.ConsumerId + "消费者.new()");

                            //新增代理类ONSConsumer实例到ONSConsumerList中
                            ONSConsumerList.Add(consumer);
                        }

                        if (!consumer.TagList.Contains(serviceTag))
                        {
                            consumer.TagList.Add(serviceTag);
                        }
                    }
                }
            }
        }
        public override TransactionStatus execute(Message value)
        {
            Console.WriteLine("execute topic: {0}, tag:{1}, key:{2}, msgId:{3},msgbody:{4}, userProperty:{5}",
                              value.getTopic(), value.getTag(), value.getKey(), value.getMsgID(), value.getBody(), value.getUserProperties("VincentNoUser"));
            // 消息 ID(有可能消息体一样,但消息 ID 不一样。当前消息 ID 在控制台无法查询)
            //string msgId = value.getMsgID();
            // 消息体内容进行 crc32, 也可以使用其它的如 MD5
            // 消息 ID 和 crc32id 主要是用来防止消息重复
            // 如果业务本身是幂等的, 可以忽略,否则需要利用 msgId 或 crc32Id 来做幂等
            // 如果要求消息绝对不重复,推荐做法是对消息体 body 使用 crc32或 md5来防止重复消息

            string            transactionType   = "Executer";
            bool              serviceResult     = false;
            TransactionStatus transactionStatus = TransactionStatus.Unknow;
            string            failureReason     = "";
            string            topic             = "";
            string            tag  = "";
            string            pid  = "";
            string            key  = "";
            string            body = "";
            string            executerMethodParameter = "";
            string            method           = "";
            string            requestTraceId   = "";
            string            producedTimesKey = "";
            int producedTimes = 0;


            try
            {
                topic                   = value.getTopic();
                tag                     = value.getTag();
                pid                     = "PID_" + value.getTopic().ToUpper();
                key                     = value.getKey();
                body                    = value.getMsgBody();
                requestTraceId          = value.getUserProperties("requestTraceId") ?? "";
                executerMethodParameter = Base64Util.Decode(body);
                producedTimesKey        = key + ":" + _ApplicationAlias + ":producedtimes";

                DebugUtil.Debug("MESSAGE_KEY:" + value.getKey() + ",ONSLocalTransaction" + transactionType + "key  " + key);

                /*在LocalTransactionExecuterExecute.execute方法中返回unknown,之后会调用LocalTransactionChecker.check方法
                 * 如果此消息topic被多个网站用作生产者,那么会导致此message会被随即传递到其他网站或当前网站中去时长调用check方法
                 * 这种传递紊乱的情况可以称为“同topic被多站点作为生产者导致check紊乱的现象”
                 * 因此如果被传递到其他网站后,需要判断当前网站是否是消息的来源网站,如果不是则返回unknown,也不记录任何记录。
                 * 如果按同topic被5个网站作为生产者,那么当execute或check出错后,能正确来到消息原始网站的概率为20%,而每次调用check历经5秒
                 * 假设是随即平均发送到5个网站随即一个中,那么平均需要历经25秒后,才能来到原始网站,因此能来到消息原始网站的平均等待时间的公式为
                 * time=n*5秒,此处n为使用该topic的网站个数。
                 * //*/
                int applicationAliasLength = _ApplicationAlias.Length;
                if (key.Substring(2, applicationAliasLength) != _ApplicationAlias)
                {
                    return(transactionStatus);
                }

                DebugUtil.Debug("MESSAGE_KEY:" + value.getKey() + ",ONSLocalTransactionExecuter.execute.after try...");
                DebugUtil.Debug("MESSAGE_KEY:" + value.getKey() + ",ONSLocalTransactionExecuter.execute.executerMethod " + value.getUserProperties("executerMethod"));
                DebugUtil.Debug("MESSAGE_KEY:" + value.getKey() + ",ONSLocalTransactionExecuter.execute.executerMethodParameter " + executerMethodParameter);

                if (ONSHelper.ExecuterMethodDictionary.ContainsKey(value.getUserProperties("executerMethod")))
                {
                    MethodInfo      methodInfo     = ONSHelper.ExecuterMethodDictionary[value.getUserProperties("executerMethod")];
                    Type            type           = methodInfo.ReflectedType;
                    Assembly        assembly       = Assembly.GetAssembly(type);
                    object          service        = assembly.CreateInstance(type.FullName);
                    ParameterInfo[] parameterInfos = methodInfo.GetParameters();

                    //DebugUtil.Log(parameterInfos[0].ParameterType.ToString());

                    method = type.FullName + ".ProcessCore";

                    //判断类型
                    if (parameterInfos[0].ParameterType.ToString().ToLower() == "system.string")
                    {
                        //string类型
                        serviceResult = (bool)methodInfo.Invoke(service, new object[] { executerMethodParameter });
                    }
                    else
                    {
                        //自定义类型
                        object parameter = JsonConvert.DeserializeObject(executerMethodParameter, parameterInfos[0].ParameterType);
                        serviceResult = (bool)methodInfo.Invoke(service, new object[] { parameter });
                    }

                    //DebugUtil.Log("MESSAGE_KEY:" + value.getKey() + ",ONSLocalTransactionExecuter.execute.body:" + body);

                    if (serviceResult)
                    {
                        // 本地事务成功则提交消息
                        transactionStatus = TransactionStatus.CommitTransaction;
                    }
                    else
                    {
                        // 本地事务失败则回滚消息
                        transactionStatus = TransactionStatus.RollbackTransaction;
                        failureReason     = method + "执行返回serviceResult为false,可能是该方法逻辑上返回serviceResult为false,也可能是该方法执行时它自己捕捉到错误返回serviceResult为false";
                    }
                }
                else
                {
                    // 不存在key则回滚消息,这里不能用RollbackTransaction,因为我们使用相同的topic在各个网站之间,这种机制会导致其他网站也会调用check方法,一旦RollbackTransaction,那么原先的网站不再重试调用check方法了,因此必须返回
                    transactionStatus = TransactionStatus.Unknow;
                    failureReason     = "ExecuterMethodDictionary中不存在key:" + value.getUserProperties("executerMethod");
                    DebugUtil.Debug("MESSAGE_KEY:" + value.getKey() + ",ONSLocalTransactionExecuter.execute.error:ExecuterMethodDictionary中不存在key:" + value.getUserProperties("executerMethod"));
                }

                //事务已经执行,尝试通过redis更新生产方法执行次数,此处如果出错是可以容忍的,但是得把错误信息记录到ProduceData中
                RedisTool RT = new RedisTool(_AliyunOnsRedisDbNumber, _RedisExchangeHosts);
                if (RT != null)
                {
                    try
                    {
                        //获取已经生产次数
                        string producedTimesValue = RT.StringGet(producedTimesKey);
                        //如果取不到
                        if (string.IsNullOrEmpty(producedTimesValue))
                        {
                            //不存在key,则新增
                            producedTimes++;
                            bool isSaved = RT.StringSet(producedTimesKey, producedTimes, TimeSpan.FromSeconds(_AliyunOnsRedisServiceResultExpireIn));
                            if (!isSaved)
                            {
                                transactionStatus = TransactionStatus.Unknow;
                            }
                        }
                        else
                        {
                            //存在key,则递增
                            int.TryParse(producedTimesValue, out producedTimes);
                            producedTimes++;
                            RT.StringIncrement(producedTimesKey);
                        }
                    }
                    catch (Exception e)
                    {
                        throw new Exception("事务已经执行,返回" + serviceResult + "。但是尝试通过redis更新生产方法执行次数时,捕捉异常:" + e.ToString());
                    }
                }
                else
                {
                    //redis有问题,导致无法实例化工具类
                    throw new Exception("事务已经执行,返回" + serviceResult + "。但是尝试通过redis更新生产方法执行次数时,无法实例化redis工具类,可能是redis服务暂不可用。");
                }
            }
            catch (Exception e)
            {
                failureReason = "事务消息在执行Executer.execute方法时捕获异常:" + e.ToString();
                DebugUtil.Debug(e.ToString());
            }
            finally
            {
                ProducerData producerData = new ProducerData(requestTraceId);
                producerData.Accomplishment   = transactionStatus != TransactionStatus.Unknow;
                producerData.ApplicationAlias = _ApplicationAlias;
                producerData.Topic            = topic;
                producerData.Tag               = tag;
                producerData.ProducerId        = pid;
                producerData.Key               = key;
                producerData.Type              = ONSMessageType.TRAN.ToString();
                producerData.Message           = executerMethodParameter;
                producerData.TransactionType   = transactionType;
                producerData.Method            = method;
                producerData.ServiceResult     = serviceResult;
                producerData.TransactionStatus = transactionStatus.ToString();
                producerData.FailureReason     = failureReason;
                producerData.ProducedTimes     = producedTimes;
                producerData.ShardingKey       = "";
                NestDataHelper.WriteData(producerData);
            }

            return(transactionStatus);
        }