def _requeue_tasks_which_unconfirmed(self):
     lock_key = f'fsdf_lock__requeue_tasks_which_unconfirmed:{self._queue_name}'
     with decorators.RedisDistributedLockContextManager(
             self.redis_db_frame,
             lock_key,
     ) as lock:
         if lock.has_aquire_lock:
             self._distributed_consumer_statistics.send_heartbeat()
             current_queue_hearbeat_ids = self._distributed_consumer_statistics.get_queue_heartbeat_ids(
                 without_time=True)
             current_queue_unacked_msg_queues = self.redis_db_frame.scan(
                 0, f'unack_{self._queue_name}_*', 100)
             for current_queue_unacked_msg_queue in current_queue_unacked_msg_queues[
                     1]:
                 current_queue_unacked_msg_queue_str = current_queue_unacked_msg_queue.decode(
                 )
                 if current_queue_unacked_msg_queue_str.split(
                         f'unack_{self._queue_name}_'
                 )[1] not in current_queue_hearbeat_ids:
                     msg_list = self.redis_db_frame.lrange(
                         current_queue_unacked_msg_queue_str, 0, -1)
                     self.logger.warning(
                         f"""{current_queue_unacked_msg_queue_str} 是掉线或关闭消费者的待确认任务, 将 一共 {len(msg_list)} 个消息,
                                         详情是 {msg_list} 推送到正常消费队列 {self._queue_name} 队列中。
                                         """)
                     self.redis_db_frame.lpush(self._queue_name, *msg_list)
                     self.redis_db_frame.delete(
                         current_queue_unacked_msg_queue_str)
예제 #2
0
 def _requeue_tasks_which_unconfirmed(self):
     ## 防止在多个进程或多个机器中同时做扫描和放入未确认消费的任务。使用个分布式锁。
     lock_key = f'fsdf_lock__requeue_tasks_which_unconfirmed_timeout:{self._queue_name}'
     with decorators.RedisDistributedLockContextManager(self.redis_db_frame, lock_key, ) as lock:
         if lock.has_aquire_lock:
             time_max = time.time() - self.UNCONFIRMED_TIMEOUT
             for value in self.redis_db_frame.zrangebyscore(self._unack_zset_name, 0, time_max):
                 self.logger.warning(f'向 {self._queue_name} 重新放入未消费确认的任务 {value}')
                 self._requeue({'body': json.loads(value)})
                 self.redis_db_frame.zrem(self._unack_zset_name, value)
             self.logger.info(f'{self._unack_zset_name} 中有待确认消费任务的数量是'
                              f' {self.redis_db_frame.zcard(self._unack_zset_name)}')
 def _requeue_tasks_which_unconfirmed(self):
     lock_key = f'fsdf_lock__requeue_tasks_which_unconfirmed:{self._queue_name}'
     with decorators.RedisDistributedLockContextManager(
             self.redis_db_frame,
             lock_key,
     ) as lock:
         if lock.has_aquire_lock:
             self._distributed_consumer_statistics.send_heartbeat()
             current_queue_hearbeat_ids = self._distributed_consumer_statistics.get_queue_heartbeat_ids(
                 without_time=True)
             xinfo_consumers = self.redis_db_frame_version3.xinfo_consumers(
                 self._queue_name, self.GROUP)
             # print(current_queue_hearbeat_ids)
             # print(xinfo_consumers)
             for xinfo_item in xinfo_consumers:
                 # print(xinfo_item)
                 if xinfo_item['idle'] > 7 * 24 * 3600 * 1000 and xinfo_item[
                         'pending'] == 0:
                     self.redis_db_frame_version3.xgroup_delconsumer(
                         self._queue_name, self.GROUP, xinfo_item['name'])
                 if xinfo_item[
                         'name'] not in current_queue_hearbeat_ids and xinfo_item[
                             'pending'] > 0:  # 说明这个消费者掉线断开或者关闭了。
                     pending_msg_list = self.redis_db_frame_version3.xpending_range(
                         self._queue_name, self.GROUP, '-', '+', 1000,
                         xinfo_item['name'])
                     if pending_msg_list:
                         # min_idle_time 不需要,因为加了分布式锁,所以不需要基于idle最小时间的判断,并且启动了基于心跳的确认消费助手,检测消费者掉线或关闭或断开的准确率100%。
                         xclaim_task_list = self.redis_db_frame_version3.xclaim(
                             self._queue_name,
                             self.GROUP,
                             self.consumer_identification,
                             force=True,
                             min_idle_time=0 * 1000,
                             message_ids=[
                                 task_item['message_id']
                                 for task_item in pending_msg_list
                             ])
                         if xclaim_task_list:
                             self.logger.warning(
                                 f' {self._queue_name}  的分组 {self.GROUP} 的消费者 {self.consumer_identification} 夺取 断开的消费者 {xinfo_item["name"]}'
                                 f'  {len(xclaim_task_list)} 个任务,详细是 {xclaim_task_list} '
                             )
                             for task in xclaim_task_list:
                                 kw = {
                                     'body': json.loads(task[1]['']),
                                     'msg_id': task[0]
                                 }
                                 self._submit_task(kw)
예제 #4
0
 def _requeue_tasks_which_unconfirmed(self):
     lock_key = f'fsdf_lock__requeue_tasks_which_unconfirmed:{self._queue_name}'
     with decorators.RedisDistributedLockContextManager(self.redis_db_frame, lock_key, ) as lock:
         if lock.has_aquire_lock:
             self._distributed_consumer_statistics.send_heartbeat()
             current_queue_hearbeat_ids = self._distributed_consumer_statistics.get_queue_heartbeat_ids(without_time=True)
             current_queue_unacked_msg_queues = self.redis_db_frame.scan(0, f'{self._queue_name}__unack_id_*', 100)
             # print(current_queue_unacked_msg_queues)
             for current_queue_unacked_msg_queue in current_queue_unacked_msg_queues[1]:
                 current_queue_unacked_msg_queue_str = current_queue_unacked_msg_queue.decode()
                 self.logger.info(f'{current_queue_unacked_msg_queue_str} 中有待确认消费任务的数量是'
                                  f' {self.redis_db_frame.zcard(current_queue_unacked_msg_queue_str)}')
                 if current_queue_unacked_msg_queue_str.split(f'{self._queue_name}__unack_id_')[1] not in current_queue_hearbeat_ids:
                     self.logger.warning(f'{current_queue_unacked_msg_queue_str} 是过期的')
                     for unacked_task_str in self.redis_db_frame.zrevrange(current_queue_unacked_msg_queue_str, 0, 1000):
                         self.logger.warning(f'从 {current_queue_unacked_msg_queue_str} 向 {self._queue_name} 重新放入未消费确认的任务 {unacked_task_str}')
                         self.redis_db_frame.rpush(self._queue_name, unacked_task_str)
                         self.redis_db_frame.zrem(current_queue_unacked_msg_queue_str, unacked_task_str)
                 else:
                     pass