Beispiel #1
0
 public static void StartToProcess(string queueName, MemcachedQueueItemHandler handler, int checkQueueIntervalMilliseconds = 5000)
 {
     StartToProcess <object>(queueName, (idx, item) =>
     {
         handler(idx, item);
         return(null);
     }, checkQueueIntervalMilliseconds);
 }
Beispiel #2
0
 public static bool Dequeue(string queueName, MemcachedQueueItemHandler handler, uint maxRetryTimes = 2)
 {
     return(Dequeue <object>(queueName, (idx, item) =>
     {
         handler(idx, item);
         return null;
     }, maxRetryTimes));
 }
Beispiel #3
0
        public static void StartToProcess <T>(string queueName, MemcachedQueueItemHandler <T> handler, int checkQueueIntervalMilliseconds = 5000)
        {
            ThreadTask task;

            if (s_ProcessTimerDicts.TryGetValue(queueName, out task) == false)
            {
                lock (s_SyncProcessTimerDicts)
                {
                    if (s_ProcessTimerDicts.TryGetValue(queueName, out task) == false)
                    {
                        task = new ThreadTask((q, m) =>
                        {
                            while (true)
                            {
                                if (s_ProcessTimerDicts.ContainsKey(q) == false)
                                {
                                    return;
                                }
                                bool hasItem;
                                do
                                {
                                    try
                                    {
                                        hasItem = Dequeue(q, handler);
                                    }
                                    catch (Exception ex)
                                    {
                                        hasItem = true;
                                        Logger.Error(ex);
                                    }
                                }while (hasItem); // 如果队列里有数据,则一直不断取数据出来处理,直到队列为空
                                // 队列取空后,休息m毫秒再尝试从队列取数据
                                Thread.Sleep(m);
                            }
                        });
                        s_ProcessTimerDicts.Add(queueName, task);
                        task.AsyncResult = task.Action.BeginInvoke(queueName, checkQueueIntervalMilliseconds, null, null);
                    }
                }
            }
        }
Beispiel #4
0
        public static bool Dequeue <T>(string queueName, MemcachedQueueItemHandler <T> handler, uint maxRetryTimes = 2)
        {
            if (maxRetryTimes < 0)
            {
                maxRetryTimes = 0;
            }
            if (string.IsNullOrWhiteSpace(queueName))
            {
                throw new ArgumentNullException("queueName");
            }
            if (CheckSerializable(typeof(T)) == false)
            {
                throw new NotSupportedException("不支持handler消息处理返回结果的类型\"" + typeof(T).FullName + "\",因为此类型不支持二进制序列化,如果要使用请在此类型的定义处添加[Serializable]的Attribute");
            }

            queueName = queueName.Trim();
            string queueId = GetQueueId(queueName);

            if (string.IsNullOrWhiteSpace(queueId)) // 队列列表里未找到指定名称的队列
            {
                //handler(-1, null);
                return(false);
            }
            ulong en_index = GetIndexById(queueId, MemcachedQueueIndexType.Enqueue);

            if (en_index <= 0) // 还从未写入过,那么肯定读取不到数据了
            {
                //handler(-1, null);
                return(false);
            }
            var client = MemcachedCacheHelper.GetClientInstance();

            MemcachedClient.CasResult casRst;
            ulong              unique;
            string             k1 = BuildIndexKey(queueId, MemcachedQueueIndexType.Dequeue);
            ulong              de_index;
            MemcachedQueueItem item;

            do
            {
                string de_index_string = client.Gets(k1, out unique) as string; // 读取上次出队列的index
                if (string.IsNullOrWhiteSpace(de_index_string) ||
                    de_index_string == "0" ||
                    ulong.TryParse(de_index_string, out de_index) == false ||
                    de_index <= 0)
                {
                    // 说明之前还从未出过队列
                    de_index = 0;
                }
                de_index++;              // 计算出本次应该出队列的item的index
                if (de_index > en_index) // 如果已经超过队列最近入的index了,说明队列已经读空了(所有item都读取过了)
                {
                    //handler(-1, null);
                    return(false);
                }
                string itemKey = BuildItemIndexKey(queueId, de_index);
                item = client.Get(itemKey) as MemcachedQueueItem;
                // 这里可能遇到一种极端的读写并发情况,即在Enqueue方法的地方先将EnqueueIndex增长上去了,但此index处的元素数据还未来得及Set写
                // 然后本Dequeue方法就先拿到此index,然后Get数据,结果因为Set还未来得及写入所以获取数据未空
                // 所以需要等待一会儿再试(期望这段等待时间内写入线程能完成此index处的数据的写入)
                int reTryTimes = 0;
                while (item == null)
                {
                    Thread.Sleep(10); // 等待10ms再试着获取此index处的数据
                    item = client.Get(itemKey) as MemcachedQueueItem;
                    reTryTimes++;
                    if (reTryTimes >= maxRetryTimes) // 如果重试达到maxRetryTimes次(累计maxRetryTimes * 10ms了),那么基本上证明不是并发还未写入了,因为并发写入问题不可能等这么久还未写入进去,基本上确定是遇到网络问题或脏数据,或者memcached服务挂了
                    {
                        break;
                    }
                    // 基本上Dequeue操作都是单线程慢慢处理,所以对执行时间要求不是那么高,500ms的延迟等待可以接受(并且是要遇到item==null的很极端的读写并发,或者是遇到了脏数据,发生的几率都很小)
                }
                if (unique == 0) // 说明还不存在,需要新增
                {
                    casRst = client.Add(k1, de_index.ToString(CultureInfo.InvariantCulture)) ? MemcachedClient.CasResult.Stored : MemcachedClient.CasResult.NotStored;
                }
                else
                {
                    casRst = client.CheckAndSet(k1, de_index.ToString(CultureInfo.InvariantCulture), unique); // 乐观锁,满足条件(没有人优先改动过)则更新缓存,如果更新成功则锁定了de_index这个索引值,其它线程无法再获取到这个index的item了
                }
            } while
            (
                casRst != MemcachedClient.CasResult.Stored || // 乐观锁,这种写法防止并发冲突
                item == null  // 发生item == null这种情况可能是脏数据了,则继续找下一个索引处的元素
            );
            if (item == null) // 说明没有找到有效数据
            {
                //handler(-1, null);
                return(false);
            }

            string    itemProcessdResultKey = BuildItemIndexKeyForProcessResult(queueId, de_index);
            T         rst = default(T);
            Exception ex  = null;

            try
            {
                rst = handler((long)de_index, item);
                ex  = null;
            }
            catch (Exception ex1)
            {
                rst = default(T);
                ex  = ex1;
                throw;
            }
            finally
            {
                MemcachedQueueItemProcessResult pr = new MemcachedQueueItemProcessResult {
                    Exception = ex, Result = rst
                };
                client.Set(itemProcessdResultKey, pr, DateTime.Now.AddMinutes(120));
            }
            return(true);
        }