funboost 23.5__py3-none-any.whl → 23.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of funboost might be problematic. Click here for more details.

funboost/__init__.py CHANGED
@@ -2,7 +2,7 @@
2
2
  from funboost.utils.dependency_packages_in_pythonpath import add_to_pythonpath # 这是把 dependency_packages_in_pythonpath 添加到 PYTHONPATH了。
3
3
 
4
4
  from funboost.utils import monkey_patches
5
- from funboost.utils import show_funboost_flag
5
+ from funboost.core import show_funboost_flag
6
6
 
7
7
  # noinspection PyUnresolvedReferences
8
8
  import nb_log
@@ -15,7 +15,11 @@ celery_app = celery.Celery(main='funboost_celery', broker=funboost_config_deaful
15
15
  task_routes={}, timezone=funboost_config_deafult.TIMEZONE, enable_utc=False, )
16
16
 
17
17
  celery_app.conf.task_acks_late = True
18
- celery_app.conf.worker_redirect_stdouts = False
18
+ celery_app.conf.update({
19
+ 'worker_redirect_stdouts': False,
20
+ 'worker_concurrency': 200
21
+ }
22
+ )
19
23
 
20
24
  logger = get_logger('funboost.CeleryHelper')
21
25
 
@@ -30,7 +34,7 @@ class CeleryHelper:
30
34
  def update_celery_app_conf(celery_app_conf: dict):
31
35
  """
32
36
  更新celery app的配置,celery app配置大全见 https://docs.celeryq.dev/en/stable/userguide/configuration.html
33
- :param celery_app_conf:
37
+ :param celery_app_conf: celery app 配置,字典
34
38
  :return:
35
39
  """
36
40
  celery_app.conf.update(celery_app_conf)
@@ -42,7 +46,7 @@ class CeleryHelper:
42
46
  for k, v in celery_app.conf.items():
43
47
  conf_dict_json_able[k] = str(v)
44
48
  # print(k, ' : ', v)
45
- print('celery app 的配置是:',json.dumps(conf_dict_json_able,ensure_ascii=False,indent=4))
49
+ print('celery app 的配置是:', json.dumps(conf_dict_json_able, ensure_ascii=False, indent=4))
46
50
 
47
51
  @staticmethod
48
52
  def celery_start_beat(beat_schedule: dict):
@@ -68,7 +72,7 @@ class CeleryHelper:
68
72
  threading.Thread(target=_f).start()
69
73
 
70
74
  @classmethod
71
- def realy_start_celery_worker(cls, worker_name=None):
75
+ def realy_start_celery_worker(cls, worker_name=None, loglevel='INFO'):
72
76
  if len(cls.to_be_start_work_celery_queue_name_set) == 0:
73
77
  raise Exception('celery worker 没有需要运行的queue')
74
78
  queue_names_str = ','.join(list(cls.to_be_start_work_celery_queue_name_set))
@@ -80,9 +84,16 @@ class CeleryHelper:
80
84
  pool_name = 'gevent'
81
85
  if cls.concurrent_mode == ConcurrentModeEnum.EVENTLET:
82
86
  pool_name = 'eventlet'
83
- argv = ['worker', f'--pool={pool_name}', '--concurrency=200',
84
- '-n', f'worker_funboost_{worker_name}@%h', f'--loglevel=INFO',
85
- f'--queues={queue_names_str}',
87
+ '''
88
+ 并发数量在app配置中已经制定了。自己用 update_celery_app_conf 方法更新就好了。
89
+ celery_app.conf.update({
90
+ 'worker_redirect_stdouts': False,
91
+ 'worker_concurrency': 200
92
+ }
93
+ '''
94
+ argv = ['worker', f'--pool={pool_name}',
95
+ '-n', f'worker_funboost_{worker_name}@%h', f'--loglevel={loglevel}',
96
+ f'--queues={queue_names_str}', # 并发数量是
86
97
  ]
87
98
  logger.info(f'celery 启动work参数 {argv}')
88
99
  celery_app.worker_main(argv)
@@ -373,6 +373,9 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
373
373
  self._consuming_function_cost_time_total_every_unit_time = 0
374
374
  self._last_execute_task_time = time.time() # 最近一次执行任务的时间。
375
375
 
376
+ self._last_show_remaining_execution_time = 0
377
+ self._show_remaining_execution_time_interval = 300
378
+
376
379
  self._msg_num_in_broker = 0
377
380
  self._last_timestamp_when_has_task_in_queue = 0
378
381
  self._last_timestamp_print_msg_num = 0
@@ -451,13 +454,13 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
451
454
 
452
455
  ''' 日志跳转代码行不正确,不用这种方式'''
453
456
 
454
- # def _log_error(self, msg, exc_info=None):
455
- # self.logger.error(msg=f'{msg} \n', exc_info=exc_info)
456
- # self.error_file_logger.error(msg=f'{msg} \n', exc_info=exc_info)
457
- #
458
- # def _log_critical(self, msg, exc_info=None):
459
- # self.logger.critical(msg=f'{msg} \n', exc_info=exc_info)
460
- # self.error_file_logger.critical(msg=f'{msg} \n', exc_info=exc_info)
457
+ def _log_error(self, msg, exc_info=None):
458
+ self.logger.error(msg=f'{msg} \n', exc_info=exc_info, extra={'sys_getframe_n': 3})
459
+ self.error_file_logger.error(msg=f'{msg} \n', exc_info=exc_info, extra={'sys_getframe_n': 3})
460
+
461
+ def _log_critical(self, msg, exc_info=None):
462
+ self.logger.critical(msg=f'{msg} \n', exc_info=exc_info, extra={'sys_getframe_n': 3})
463
+ self.error_file_logger.critical(msg=f'{msg} \n', exc_info=exc_info, extra={'sys_getframe_n': 3})
461
464
 
462
465
  @property
463
466
  @decorators.synchronized
@@ -492,8 +495,9 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
492
495
  except BaseException as e:
493
496
  log_msg = func.__name__ + ' 运行出错\n ' + traceback.format_exc(
494
497
  limit=10) if is_display_detail_exception else str(e)
495
- self.logger.error(msg=f'{log_msg} \n', exc_info=True)
496
- self.error_file_logger.error(msg=f'{log_msg} \n', exc_info=True)
498
+ # self.logger.error(msg=f'{log_msg} \n', exc_info=True)
499
+ # self.error_file_logger.error(msg=f'{log_msg} \n', exc_info=True)
500
+ self._log_error(msg=log_msg, exc_info=True)
497
501
  finally:
498
502
  time.sleep(time_sleep)
499
503
 
@@ -524,9 +528,10 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
524
528
  self._distributed_consumer_statistics.run()
525
529
  self.logger.warning(f'启动了分布式环境 使用 redis 的键 hearbeat:{self._queue_name} 统计活跃消费者 ,当前消费者唯一标识为 {self.consumer_identification}')
526
530
 
527
- self.keep_circulating(10, block=False)(self.check_heartbeat_and_message_count)() # 间隔时间最好比self._unit_time_for_count小整数倍,不然日志不准。
531
+ self.keep_circulating(60, block=False)(self.check_heartbeat_and_message_count)() # 间隔时间最好比self._unit_time_for_count小整数倍,不然日志不准。
528
532
  if self._is_support_remote_kill_task:
529
- kill_remote_task.RemoteTaskKiller(self.queue_name, None).start_cycle_kill_task()
533
+ self.keep_circulating(10, block=False)(kill_remote_task.RemoteTaskKiller(self.queue_name, None).start_cycle_kill_task)()
534
+ self._is_show_message_get_from_broker = True # 方便用户看到从消息队列取出来的消息的task_id,然后使用task_id杀死运行中的消息。
530
535
  if self._do_task_filtering:
531
536
  self._redis_filter.delete_expire_filter_task_cycle() # 这个默认是RedisFilter类,是个pass不运行。所以用别的消息中间件模式,不需要安装和配置redis。
532
537
  if self._schedule_tasks_on_main_thread:
@@ -739,8 +744,9 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
739
744
  if self._is_push_to_dlx_queue_when_retry_max_times:
740
745
  log_msg += f' 。发送到死信队列 {self._dlx_queue_name} 中'
741
746
  self.publisher_of_dlx_queue.publish(kw['body'])
742
- self.logger.critical(msg=f'{log_msg} \n', )
743
- self.error_file_logger.critical(msg=f'{log_msg} \n')
747
+ # self.logger.critical(msg=f'{log_msg} \n', )
748
+ # self.error_file_logger.critical(msg=f'{log_msg} \n')
749
+ self._log_critical(msg=log_msg)
744
750
 
745
751
  if self._get_priority_conf(kw, 'is_using_rpc_mode'):
746
752
  # print(function_result_status.get_status_dict(without_datetime_obj=
@@ -760,23 +766,26 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
760
766
  if time.time() - self._current_time_for_execute_task_times_every_unit_time > self._unit_time_for_count:
761
767
  avarage_function_spend_time = round(self._consuming_function_cost_time_total_every_unit_time / self._execute_task_times_every_unit_time, 4)
762
768
  msg = f'{self._unit_time_for_count} 秒内执行了 {self._execute_task_times_every_unit_time} 次函数 [ {self.consuming_function.__name__} ] ,' \
763
- f'函数平均运行耗时 {avarage_function_spend_time} '
764
- if self._msg_num_in_broker != -1: # 有的中间件无法统计或没实现统计队列剩余数量的,统一返回的是-1,不显示这句话。
769
+ f'函数平均运行耗时 {avarage_function_spend_time} 秒。 '
770
+ self.logger.debug(msg)
771
+ if self._msg_num_in_broker != -1 and time.time() - self._last_show_remaining_execution_time > self._show_remaining_execution_time_interval: # 有的中间件无法统计或没实现统计队列剩余数量的,统一返回的是-1,不显示这句话。
765
772
  # msg += f''' ,预计还需要 {time_util.seconds_to_hour_minute_second(self._msg_num_in_broker * avarage_function_spend_time / active_consumer_num)} 时间 才能执行完成 {self._msg_num_in_broker}个剩余的任务'''
766
773
  need_time = time_util.seconds_to_hour_minute_second(self._msg_num_in_broker / (self._execute_task_times_every_unit_time / self._unit_time_for_count) /
767
774
  self._distributed_consumer_statistics.active_consumer_num)
768
- msg += f''' ,预计还需要 {need_time}''' + \
769
- f''' 时间 才能执行完成 {self._msg_num_in_broker}个剩余的任务'''
770
- self.logger.info(msg)
775
+ msg += f''' 预计还需要 {need_time} 时间 才能执行完成 队列 {self.queue_name} 中的 {self._msg_num_in_broker} 个剩余任务'''
776
+ self.logger.info(msg)
777
+ self._last_show_remaining_execution_time = time.time()
771
778
  self._current_time_for_execute_task_times_every_unit_time = time.time()
772
779
  self._consuming_function_cost_time_total_every_unit_time = 0
773
780
  self._execute_task_times_every_unit_time = 0
781
+
774
782
  if self._user_custom_record_process_info_func:
775
783
  self._user_custom_record_process_info_func(current_function_result_status)
776
784
  except BaseException as e:
777
785
  log_msg = f' error 严重错误 {type(e)} {e} '
778
- self.logger.critical(msg=f'{log_msg} \n', exc_info=True)
779
- self.error_file_logger.critical(msg=f'{log_msg} \n', exc_info=True)
786
+ # self.logger.critical(msg=f'{log_msg} \n', exc_info=True)
787
+ # self.error_file_logger.critical(msg=f'{log_msg} \n', exc_info=True)
788
+ self._log_critical(msg=log_msg, exc_info=True)
780
789
 
781
790
  # noinspection PyProtectedMember
782
791
  def _run_consuming_function_with_confirm_and_retry(self, kw: dict, current_retry_times,
@@ -795,12 +804,13 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
795
804
  function_result_status._has_kill_task = True
796
805
  self.logger.warning(f'取消运行 {task_id} {function_only_params}')
797
806
  return function_result_status
798
- function_run = kill_remote_task.kill_fun_deco(task_id)(function_run) # 用杀死装饰器包装起来在另一个线程运行函数
807
+ function_run = kill_remote_task.kill_fun_deco(task_id)(function_run) # 用杀死装饰器包装起来在另一个线程运行函数,以便等待远程杀死。
799
808
  function_result_status.result = function_run(**function_only_params)
800
809
  if asyncio.iscoroutine(function_result_status.result):
801
810
  log_msg = f'''异步的协程消费函数必须使用 async 并发模式并发,请设置消费函数 {self.consuming_function.__name__} 的concurrent_mode 为 ConcurrentModeEnum.ASYNC 或 4'''
802
- self.logger.critical(msg=f'{log_msg} \n')
803
- self.error_file_logger.critical(msg=f'{log_msg} \n')
811
+ # self.logger.critical(msg=f'{log_msg} \n')
812
+ # self.error_file_logger.critical(msg=f'{log_msg} \n')
813
+ self._log_critical(msg=log_msg)
804
814
  # noinspection PyProtectedMember,PyUnresolvedReferences
805
815
 
806
816
  os._exit(4)
@@ -813,8 +823,9 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
813
823
  except BaseException as e:
814
824
  if isinstance(e, (ExceptionForRequeue,)): # mongo经常维护备份时候插入不了或挂了,或者自己主动抛出一个ExceptionForRequeue类型的错误会重新入队,不受指定重试次数逇约束。
815
825
  log_msg = f'函数 [{self.consuming_function.__name__}] 中发生错误 {type(e)} {e} 。消息重新放入当前队列 {self._queue_name}'
816
- self.logger.critical(msg=f'{log_msg} \n')
817
- self.error_file_logger.critical(msg=f'{log_msg} \n')
826
+ # self.logger.critical(msg=f'{log_msg} \n')
827
+ # self.error_file_logger.critical(msg=f'{log_msg} \n')
828
+ self._log_critical(msg=log_msg)
818
829
  time.sleep(0.1) # 防止快速无限出错入队出队,导致cpu和中间件忙
819
830
  # 重回队列如果不修改task_id,insert插入函数消费状态结果到mongo会主键重复。要么保存函数消费状态使用replace,要么需要修改taskikd
820
831
  # kw_new = copy.deepcopy(kw)
@@ -825,21 +836,25 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
825
836
  function_result_status._has_requeue = True
826
837
  if isinstance(e, ExceptionForPushToDlxqueue):
827
838
  log_msg = f'函数 [{self.consuming_function.__name__}] 中发生错误 {type(e)} {e},消息放入死信队列 {self._dlx_queue_name}'
828
- self.logger.critical(msg=f'{log_msg} \n')
829
- self.error_file_logger.critical(msg=f'{log_msg} \n')
839
+ # self.logger.critical(msg=f'{log_msg} \n')
840
+ # self.error_file_logger.critical(msg=f'{log_msg} \n')
841
+ self._log_critical(msg=log_msg)
830
842
  self.publisher_of_dlx_queue.publish(kw['body']) # 发布到死信队列,不重回当前队列
831
843
  function_result_status._has_to_dlx_queue = True
832
844
  if isinstance(e, kill_remote_task.TaskHasKilledError):
833
845
  log_msg = f'task_id 为 {task_id} , 函数 [{self.consuming_function.__name__}] 运行入参 {function_only_params} ,已被远程指令杀死 {type(e)} {e}'
834
- self.logger.critical(msg=f'{log_msg} ')
835
- self.error_file_logger.critical(msg=f'{log_msg} ')
846
+ # self.logger.critical(msg=f'{log_msg} ')
847
+ # self.error_file_logger.critical(msg=f'{log_msg} ')
848
+ self._log_critical(msg=log_msg)
836
849
  function_result_status._has_kill_task = True
837
850
  if isinstance(e, (ExceptionForRequeue, ExceptionForPushToDlxqueue, kill_remote_task.TaskHasKilledError)):
838
851
  return function_result_status
839
852
  log_msg = f'''函数 {self.consuming_function.__name__} 第{current_retry_times + 1}次运行发生错误,
840
- 函数运行时间是 {round(time.time() - t_start, 4)} 秒,\n 入参是 {function_only_params} \n 原因是 {type(e)} {e} '''
841
- self.logger.error(msg=f'{log_msg} \n', exc_info=self._get_priority_conf(kw, 'is_print_detail_exception'))
842
- self.error_file_logger.error(msg=f'{log_msg} \n', exc_info=self._get_priority_conf(kw, 'is_print_detail_exception'))
853
+ 函数运行时间是 {round(time.time() - t_start, 4)} 秒, 入参是 {function_only_params}
854
+ {type(e)} {e} '''
855
+ # self.logger.error(msg=f'{log_msg} \n', exc_info=self._get_priority_conf(kw, 'is_print_detail_exception'))
856
+ # self.error_file_logger.error(msg=f'{log_msg} \n', exc_info=self._get_priority_conf(kw, 'is_print_detail_exception'))
857
+ self._log_error(msg=log_msg, exc_info=self._get_priority_conf(kw, 'is_print_detail_exception'))
843
858
  # traceback.print_exc()
844
859
  function_result_status.exception = f'{e.__class__.__name__} {str(e)}'
845
860
  function_result_status.result = FunctionResultStatus.FUNC_RUN_ERROR
@@ -876,8 +891,9 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
876
891
  if self._is_push_to_dlx_queue_when_retry_max_times:
877
892
  log_msg += f' 。发送到死信队列 {self._dlx_queue_name} 中'
878
893
  await simple_run_in_executor(self.publisher_of_dlx_queue.publish, kw['body'])
879
- self.logger.critical(msg=f'{log_msg} \n', )
880
- self.error_file_logger.critical(msg=f'{log_msg} \n')
894
+ # self.logger.critical(msg=f'{log_msg} \n', )
895
+ # self.error_file_logger.critical(msg=f'{log_msg} \n')
896
+ self._log_critical(msg=log_msg)
881
897
 
882
898
  # self._confirm_consume(kw) # 错得超过指定的次数了,就确认消费了。
883
899
  if self._get_priority_conf(kw, 'is_using_rpc_mode'):
@@ -898,24 +914,26 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
898
914
  if time.time() - self._current_time_for_execute_task_times_every_unit_time > self._unit_time_for_count:
899
915
  avarage_function_spend_time = round(self._consuming_function_cost_time_total_every_unit_time / self._execute_task_times_every_unit_time, 4)
900
916
  msg = f'{self._unit_time_for_count} 秒内执行了 {self._execute_task_times_every_unit_time} 次函数 [ {self.consuming_function.__name__} ] ,' \
901
- f'函数平均运行耗时 {avarage_function_spend_time} '
902
- if self._msg_num_in_broker != -1:
903
- if self._msg_num_in_broker != -1: # 有的中间件无法统计或没实现统计队列剩余数量的,统一返回的是-1,不显示这句话。
904
- # msg += f''' ,预计还需要 {time_util.seconds_to_hour_minute_second(self._msg_num_in_broker * avarage_function_spend_time / active_consumer_num)} 时间 才能执行完成 {self._msg_num_in_broker}个剩余的任务'''
905
- need_time = time_util.seconds_to_hour_minute_second(self._msg_num_in_broker / (self._execute_task_times_every_unit_time / self._unit_time_for_count) /
906
- self._distributed_consumer_statistics.active_consumer_num)
907
- msg += f''' ,预计还需要 {need_time}''' + \
908
- f''' 时间 才能执行完成 {self._msg_num_in_broker}个剩余的任务'''
909
- self.logger.info(msg)
917
+ f'函数平均运行耗时 {avarage_function_spend_time} 秒。 '
918
+ self.logger.debug(msg)
919
+ if self._msg_num_in_broker != -1 and time.time() - self._last_show_remaining_execution_time > self._show_remaining_execution_time_interval: # 有的中间件无法统计或没实现统计队列剩余数量的,统一返回的是-1,不显示这句话。
920
+ # msg += f''' ,预计还需要 {time_util.seconds_to_hour_minute_second(self._msg_num_in_broker * avarage_function_spend_time / active_consumer_num)} 时间 才能执行完成 {self._msg_num_in_broker}个剩余的任务'''
921
+ need_time = time_util.seconds_to_hour_minute_second(self._msg_num_in_broker / (self._execute_task_times_every_unit_time / self._unit_time_for_count) /
922
+ self._distributed_consumer_statistics.active_consumer_num)
923
+ msg += f''' 预计还需要 {need_time} 时间 才能执行完成 队列 {self.queue_name} 中的 {self._msg_num_in_broker} 个剩余任务'''
924
+ self.logger.info(msg)
925
+ self._last_show_remaining_execution_time = time.time()
910
926
  self._current_time_for_execute_task_times_every_unit_time = time.time()
911
927
  self._consuming_function_cost_time_total_every_unit_time = 0
912
928
  self._execute_task_times_every_unit_time = 0
929
+
913
930
  if self._user_custom_record_process_info_func:
914
931
  await self._user_custom_record_process_info_func(current_function_result_status)
915
932
  except BaseException as e:
916
933
  log_msg = f' error 严重错误 {type(e)} {e} '
917
- self.logger.critical(msg=f'{log_msg} \n', exc_info=True)
918
- self.error_file_logger.critical(msg=f'{log_msg} \n', exc_info=True)
934
+ # self.logger.critical(msg=f'{log_msg} \n', exc_info=True)
935
+ # self.error_file_logger.critical(msg=f'{log_msg} \n', exc_info=True)
936
+ self._log_critical(msg=log_msg, exc_info=True)
919
937
 
920
938
  # noinspection PyProtectedMember
921
939
  async def _async_run_consuming_function_with_confirm_and_retry(self, kw: dict, current_retry_times,
@@ -930,8 +948,9 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
930
948
  corotinue_obj = self.consuming_function(**function_only_params)
931
949
  if not asyncio.iscoroutine(corotinue_obj):
932
950
  log_msg = f'''当前设置的并发模式为 async 并发模式,但消费函数不是异步协程函数,请不要把消费函数 {self.consuming_function.__name__} 的 concurrent_mode 设置为 4'''
933
- self.logger.critical(msg=f'{log_msg} \n')
934
- self.error_file_logger.critical(msg=f'{log_msg} \n')
951
+ # self.logger.critical(msg=f'{log_msg} \n')
952
+ # self.error_file_logger.critical(msg=f'{log_msg} \n')
953
+ self._log_critical(msg=log_msg)
935
954
  # noinspection PyProtectedMember,PyUnresolvedReferences
936
955
  os._exit(444)
937
956
  if self._function_timeout == 0:
@@ -949,8 +968,9 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
949
968
  except BaseException as e:
950
969
  if isinstance(e, (ExceptionForRequeue,)): # mongo经常维护备份时候插入不了或挂了,或者自己主动抛出一个ExceptionForRequeue类型的错误会重新入队,不受指定重试次数逇约束。
951
970
  log_msg = f'函数 [{self.consuming_function.__name__}] 中发生错误 {type(e)} {e} 。 消息重新放入当前队列 {self._queue_name}'
952
- self.logger.critical(msg=f'{log_msg} \n')
953
- self.error_file_logger.critical(msg=f'{log_msg} \n')
971
+ # self.logger.critical(msg=f'{log_msg} \n')
972
+ # self.error_file_logger.critical(msg=f'{log_msg} \n')
973
+ self._log_critical(msg=log_msg)
954
974
  # time.sleep(1) # 防止快速无限出错入队出队,导致cpu和中间件忙
955
975
  await asyncio.sleep(0.1)
956
976
  # return self._requeue(kw)
@@ -958,16 +978,19 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
958
978
  function_result_status._has_requeue = True
959
979
  if isinstance(e, ExceptionForPushToDlxqueue):
960
980
  log_msg = f'函数 [{self.consuming_function.__name__}] 中发生错误 {type(e)} {e},消息放入死信队列 {self._dlx_queue_name}'
961
- self.logger.critical(msg=f'{log_msg} \n')
962
- self.error_file_logger.critical(msg=f'{log_msg} \n')
981
+ # self.logger.critical(msg=f'{log_msg} \n')
982
+ # self.error_file_logger.critical(msg=f'{log_msg} \n')
983
+ self._log_critical(msg=log_msg)
963
984
  await simple_run_in_executor(self.publisher_of_dlx_queue.publish, kw['body']) # 发布到死信队列,不重回当前队列
964
985
  function_result_status._has_to_dlx_queue = True
965
986
  if isinstance(e, (ExceptionForRequeue, ExceptionForPushToDlxqueue)):
966
987
  return function_result_status
967
988
  log_msg = f'''函数 {self.consuming_function.__name__} 第{current_retry_times + 1}次运行发生错误,
968
- 函数运行时间是 {round(time.time() - t_start, 4)} 秒,\n 入参是 {function_only_params} \n 原因是 {type(e)} {e} '''
969
- self.logger.error(msg=f'{log_msg} \n', exc_info=self._get_priority_conf(kw, 'is_print_detail_exception'))
970
- self.error_file_logger.error(msg=f'{log_msg} \n', exc_info=self._get_priority_conf(kw, 'is_print_detail_exception'))
989
+ 函数运行时间是 {round(time.time() - t_start, 4)} 秒, 入参是 {function_only_params}
990
+ 原因是 {type(e)} {e} '''
991
+ # self.logger.error(msg=f'{log_msg} \n', exc_info=self._get_priority_conf(kw, 'is_print_detail_exception'))
992
+ # self.error_file_logger.error(msg=f'{log_msg} \n', exc_info=self._get_priority_conf(kw, 'is_print_detail_exception'))
993
+ self._log_error(msg=log_msg, exc_info=self._get_priority_conf(kw, 'is_print_detail_exception'))
971
994
  function_result_status.exception = f'{e.__class__.__name__} {str(e)}'
972
995
  function_result_status.result = FunctionResultStatus.FUNC_RUN_ERROR
973
996
  return function_result_status
@@ -1004,8 +1027,9 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
1004
1027
  misfire_grace_time = self._get_priority_conf(event.function_kwargs["kw"], 'misfire_grace_time')
1005
1028
  log_msg = f''' 现在时间是 {time_util.DatetimeConverter().datetime_str} ,比此任务规定的本应该的运行时间 {event.scheduled_run_time} 相比 超过了指定的 {misfire_grace_time} 秒,放弃执行此任务
1006
1029
  {event.function_kwargs["kw"]["body"]} '''
1007
- self.logger.critical(msg=f'{log_msg} \n')
1008
- self.error_file_logger.critical(msg=f'{log_msg} \n')
1030
+ # self.logger.critical(msg=f'{log_msg} \n')
1031
+ # self.error_file_logger.critical(msg=f'{log_msg} \n')
1032
+ self._log_critical(msg=log_msg)
1009
1033
  self._confirm_consume(event.function_kwargs["kw"])
1010
1034
 
1011
1035
  '''
@@ -156,13 +156,29 @@ class CeleryConsumer(AbstractConsumer):
156
156
  '''
157
157
 
158
158
  def custom_init(self):
159
- # 这就是核心,@boost时候回注册任务路由到celery_app
159
+ # 这就是核心,@boost时候会 @ celery app.task装饰器
160
160
  @celery_app.task(name=self.queue_name, rate_limit=f'{self._qps}/s', soft_time_limit=self._function_timeout,
161
161
  max_retries=self._max_retry_times,
162
- **self.broker_exclusive_config['celery_task_config'])
163
- def f(*args, **kwargs):
162
+ **self.broker_exclusive_config['celery_task_config'],
163
+ bind=True)
164
+ def f(this, *args, **kwargs):
164
165
  self.logger.debug(f' 这条消息是 celery 从 {self.queue_name} 队列中取出 ,是由 celery 框架调度 {self.consuming_function.__name__} 函数处理: args: {args} , kwargs: {kwargs}')
165
- return self.consuming_function(*args, **kwargs)
166
+ # return self.consuming_function(*args, **kwargs) # 如果没有声明 autoretry_for ,那么消费函数出错了就不会自动重试了。
167
+ try:
168
+ return self.consuming_function(*args, **kwargs)
169
+ except BaseException as exc: # 改成自动重试。
170
+ # print(this.request.__dict__,dir(this))
171
+
172
+ if this.request.retries != self._max_retry_times:
173
+ log_msg = f'fun: {self.consuming_function} args: {args} , kwargs: {kwargs} 消息第{this.request.retries}次运行出错, {exc} \n'
174
+ self._log_error(log_msg, exc_info=self._is_print_detail_exception)
175
+ else:
176
+ log_msg = f'fun: {self.consuming_function} args: {args} , kwargs: {kwargs} 消息达到最大重试次数{this.request.retries}次仍然出错, {exc} \n'
177
+ self._log_critical(log_msg, exc_info=self._is_print_detail_exception)
178
+ # 发生异常,尝试重试任务,countdown 是多少秒后重试
179
+ raise this.retry(exc=exc, countdown=5)
180
+
181
+ celery_app.conf.task_routes.update({self.queue_name: {"queue": self.queue_name}}) # 自动配置celery每个函数使用不同的队列名。
166
182
  self.celery_task = f
167
183
  CeleryHelper.concurrent_mode = self._concurrent_mode
168
184
 
@@ -29,7 +29,7 @@ class RabbitmqConsumerAmqpStorm(AbstractConsumer):
29
29
  rp = RabbitmqPublisherUsingAmqpStorm(self.queue_name,broker_exclusive_config=self.broker_exclusive_config)
30
30
  rp.init_broker()
31
31
  rp.channel_wrapper_by_ampqstormbaic.qos(self._concurrent_num)
32
- rp.channel_wrapper_by_ampqstormbaic.consume(callback=callback, queue=self.queue_name, no_ack=False)
32
+ rp.channel_wrapper_by_ampqstormbaic.consume(callback=callback, queue=self.queue_name, no_ack=False,)
33
33
  rp.channel.start_consuming(auto_decode=True)
34
34
 
35
35
  def _confirm_consume(self, kw):
@@ -156,7 +156,7 @@ class RedisConsumerAckAble(ConsumerConfirmMixinWithTheHelpOfRedisByHearbeat, Abs
156
156
  kw = {'body': task_dict, 'task_str': task_str}
157
157
  self._submit_task(kw)
158
158
  else:
159
- time.sleep(0.5)
159
+ time.sleep(0.2)
160
160
 
161
161
  def _requeue(self, kw):
162
162
  self.redis_db_frame.rpush(self._queue_name, json.dumps(kw['body']))
@@ -10,6 +10,9 @@
10
10
  """
11
11
  import json
12
12
  import time
13
+
14
+ import redis3
15
+
13
16
  from funboost.consumers.redis_consumer_ack_able import RedisConsumerAckAble
14
17
 
15
18
 
@@ -49,7 +52,7 @@ class RedisPriorityConsumer(RedisConsumerAckAble):
49
52
 
50
53
  BROKER_EXCLUSIVE_CONFIG_DEFAULT = {'x-max-priority': None} # x-max-priority 是 rabbitmq的优先级队列配置,必须为整数,强烈建议要小于5。为None就代表队列不支持优先级。
51
54
 
52
- def _shedual_task(self):
55
+ def _shedual_task0000(self):
53
56
 
54
57
  while True:
55
58
  # task_str_list = script(keys=[queues_str, self._unack_zset_name], args=[time.time()])
@@ -64,5 +67,31 @@ class RedisPriorityConsumer(RedisConsumerAckAble):
64
67
  kw = {'body': task_dict, 'task_str': msg}
65
68
  self._submit_task(kw)
66
69
 
70
+ def _shedual_task(self):
71
+ """https://redis.readthedocs.io/en/latest/advanced_features.html#default-pipelines """
72
+ while True:
73
+ # task_str_list = script(keys=[queues_str, self._unack_zset_name], args=[time.time()])
74
+ while True:
75
+ try:
76
+ with self.redis_db_frame_version3.pipeline() as p:
77
+ p.watch(self._unack_zset_name, *self.publisher_of_same_queue.queue_list, )
78
+ task_tuple = p.blpop(keys=self.publisher_of_same_queue.queue_list, timeout=60) # 监听了多个键名,所以间接实现了优先级,和kombu的redis 支持优先级的设计思路不谋而合。
79
+ # print(task_tuple)
80
+ if task_tuple:
81
+ msg = task_tuple[1]
82
+ p.zadd(self._unack_zset_name, {msg: time.time()})
83
+ # self.logger.debug(task_tuple)
84
+ p.unwatch()
85
+ p.execute()
86
+ break
87
+ except redis3.WatchError:
88
+ continue
89
+ if task_tuple:
90
+ self._print_message_get_from_broker('redis', msg)
91
+ # self.logger.debug(f'从redis的 [{self._queue_name}] 队列中 取出的消息是: {task_str_list} ')
92
+ task_dict = json.loads(msg)
93
+ kw = {'body': task_dict, 'task_str': msg}
94
+ self._submit_task(kw)
95
+
67
96
  def _requeue(self, kw):
68
97
  self.publisher_of_same_queue.publish(kw['body'])
@@ -0,0 +1,48 @@
1
+ import nb_log
2
+
3
+ logger = nb_log.get_logger('funboost.show_funboost_flag')
4
+
5
+ funboost_flag_str = '''
6
+
7
+
8
+ FFFFFFFFFFFFFFFFFFFFFF UUUUUUUU UUUUUUUU NNNNNNNN NNNNNNNN BBBBBBBBBBBBBBBBB OOOOOOOOO OOOOOOOOO SSSSSSSSSSSSSSS TTTTTTTTTTTTTTTTTTTTTTT
9
+ F::::::::::::::::::::F U::::::U U::::::U N:::::::N N::::::N B::::::::::::::::B OO:::::::::OO OO:::::::::OO SS:::::::::::::::S T:::::::::::::::::::::T
10
+ F::::::::::::::::::::F U::::::U U::::::U N::::::::N N::::::N B::::::BBBBBB:::::B OO:::::::::::::OO OO:::::::::::::OO S:::::SSSSSS::::::S T:::::::::::::::::::::T
11
+ FF::::::FFFFFFFFF::::F UU:::::U U:::::UU N:::::::::N N::::::N BB:::::B B:::::B O:::::::OOO:::::::O O:::::::OOO:::::::O S:::::S SSSSSSS T:::::TT:::::::TT:::::T
12
+ F:::::F FFFFFF U:::::U U:::::U N::::::::::N N::::::N B::::B B:::::B O::::::O O::::::O O::::::O O::::::O S:::::S TTTTTT T:::::T TTTTTT
13
+ F:::::F U:::::D D:::::U N:::::::::::N N::::::N B::::B B:::::B O:::::O O:::::O O:::::O O:::::O S:::::S T:::::T
14
+ F::::::FFFFFFFFFF U:::::D D:::::U N:::::::N::::N N::::::N B::::BBBBBB:::::B O:::::O O:::::O O:::::O O:::::O S::::SSSS T:::::T
15
+ F:::::::::::::::F U:::::D D:::::U N::::::N N::::N N::::::N B:::::::::::::BB O:::::O O:::::O O:::::O O:::::O SS::::::SSSSS T:::::T
16
+ F:::::::::::::::F U:::::D D:::::U N::::::N N::::N:::::::N B::::BBBBBB:::::B O:::::O O:::::O O:::::O O:::::O SSS::::::::SS T:::::T
17
+ F::::::FFFFFFFFFF U:::::D D:::::U N::::::N N:::::::::::N B::::B B:::::B O:::::O O:::::O O:::::O O:::::O SSSSSS::::S T:::::T
18
+ F:::::F U:::::D D:::::U N::::::N N::::::::::N B::::B B:::::B O:::::O O:::::O O:::::O O:::::O S:::::S T:::::T
19
+ F:::::F U::::::U U::::::U N::::::N N:::::::::N B::::B B:::::B O::::::O O::::::O O::::::O O::::::O S:::::S T:::::T
20
+ FF:::::::FF U:::::::UUU:::::::U N::::::N N::::::::N BB:::::BBBBBB::::::B O:::::::OOO:::::::O O:::::::OOO:::::::O SSSSSSS S:::::S TT:::::::TT
21
+ F::::::::FF UU:::::::::::::UU N::::::N N:::::::N B:::::::::::::::::B OO:::::::::::::OO OO:::::::::::::OO S::::::SSSSSS:::::S T:::::::::T
22
+ F::::::::FF UU:::::::::UU N::::::N N::::::N B::::::::::::::::B OO:::::::::OO OO:::::::::OO S:::::::::::::::SS T:::::::::T
23
+ FFFFFFFFFFF UUUUUUUUU NNNNNNNN NNNNNNN BBBBBBBBBBBBBBBBB OOOOOOOOO OOOOOOOOO SSSSSSSSSSSSSSS TTTTTTTTTTT
24
+
25
+
26
+ '''
27
+
28
+ funboost_flag_str2 = r'''
29
+
30
+ ___ ___ ___ ___ ___ ___
31
+ / /\ /__/\ /__/\ _____ / /\ / /\ / /\ ___
32
+ / /:/_ \ \:\ \ \:\ / /::\ / /::\ / /::\ / /:/_ / /\
33
+ / /:/ /\ \ \:\ \ \:\ / /:/\:\ / /:/\:\ / /:/\:\ / /:/ /\ / /:/
34
+ / /:/ /:/ ___ \ \:\ _____\__\:\ / /:/~/::\ / /:/ \:\ / /:/ \:\ / /:/ /::\ / /:/
35
+ /__/:/ /:/ /__/\ \__\:\ /__/::::::::\ /__/:/ /:/\:| /__/:/ \__\:\ /__/:/ \__\:\ /__/:/ /:/\:\ / /::\
36
+ \ \:\/:/ \ \:\ / /:/ \ \:\~~\~~\/ \ \:\/:/~/:/ \ \:\ / /:/ \ \:\ / /:/ \ \:\/:/~/:/ /__/:/\:\
37
+ \ \::/ \ \:\ /:/ \ \:\ ~~~ \ \::/ /:/ \ \:\ /:/ \ \:\ /:/ \ \::/ /:/ \__\/ \:\
38
+ \ \:\ \ \:\/:/ \ \:\ \ \:\/:/ \ \:\/:/ \ \:\/:/ \__\/ /:/ \ \:\
39
+ \ \:\ \ \::/ \ \:\ \ \::/ \ \::/ \ \::/ /__/:/ \__\/
40
+ \__\/ \__\/ \__\/ \__\/ \__\/ \__\/ \__\/
41
+
42
+
43
+
44
+ '''
45
+
46
+ logger.debug('\033[0m' + funboost_flag_str2 + '\033[0m')
47
+
48
+ logger.info(f'''分布式函数调度框架funboost文档地址: \033[0m https://funboost.readthedocs.io/zh/latest/ \033[0m ''')
@@ -27,7 +27,7 @@ from funboost.utils.simple_data_class import DataClassBase
27
27
  # $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ 以下是中间件连接配置 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
28
28
 
29
29
 
30
- MONGO_CONNECT_URL = f'mongodb://127.0.0.1:27017' # 如果有密码连接 'mongodb://myUserAdmin:8mwTdy1klnSYepNo@192.168.199.202:27016/MONGO_CONNECT_URL = 'mongodb://root:123456@192.168.64.151:27017?authSource=admin''
30
+ MONGO_CONNECT_URL = f'mongodb://127.0.0.1:27017' # 如果有密码连接 'mongodb://myUserAdmin:8mwTdy1klnSYepNo@192.168.199.202:27016/' authSource 指定鉴权db,MONGO_CONNECT_URL = 'mongodb://root:123456@192.168.64.151:27017?authSource=admin'
31
31
 
32
32
  RABBITMQ_USER = 'rabbitmq_user'
33
33
  RABBITMQ_PASS = 'rabbitmq_pass'
@@ -199,7 +199,7 @@ class AbstractPublisher(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
199
199
 
200
200
  def _convert_msg(self, msg: typing.Union[str, dict], task_id=None,
201
201
  priority_control_config: PriorityConsumingControlConfig = None) -> (typing.Dict, typing.Dict, typing.Dict):
202
- if isinstance(msg, (str,bytes)):
202
+ if isinstance(msg, (str, bytes)):
203
203
  msg = json.loads(msg)
204
204
  msg_function_kw = copy.deepcopy(msg)
205
205
  raw_extra = {}
@@ -215,7 +215,7 @@ class AbstractPublisher(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
215
215
  extra_params.update(priority_control_config.to_dict())
216
216
  extra_params.update(raw_extra)
217
217
  msg['extra'] = extra_params
218
- return msg, msg_function_kw, extra_params,task_id
218
+ return msg, msg_function_kw, extra_params, task_id
219
219
 
220
220
  def publish(self, msg: typing.Union[str, dict], task_id=None,
221
221
  priority_control_config: PriorityConsumingControlConfig = None):
@@ -226,7 +226,7 @@ class AbstractPublisher(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
226
226
  :param priority_control_config:优先级配置,消息可以携带优先级配置,覆盖boost的配置。
227
227
  :return:
228
228
  """
229
- msg, msg_function_kw, extra_params,task_id = self._convert_msg(msg, task_id, priority_control_config)
229
+ msg, msg_function_kw, extra_params, task_id = self._convert_msg(msg, task_id, priority_control_config)
230
230
  t_start = time.time()
231
231
  decorators.handle_exception(retry_times=10, is_throw_error=True, time_sleep=0.1)(
232
232
  self.concrete_realization_of_publish)(json.dumps(msg, ensure_ascii=False))
@@ -3,11 +3,7 @@
3
3
  # @Time : 2022/8/8 0008 12:12
4
4
  import os
5
5
  import sys
6
- import uuid
7
- import copy
8
6
  import time
9
- import threading
10
- import json
11
7
  import celery
12
8
  import celery.result
13
9
  import typing
@@ -20,24 +16,6 @@ class CeleryPublisher(AbstractPublisher, ):
20
16
  """
21
17
  使用celery作为中间件
22
18
  """
23
- celery_conf_lock = threading.Lock()
24
-
25
- # noinspection PyAttributeOutsideInit
26
- def custom_init(self):
27
- # self.broker_exclusive_config['task_routes'] = {self.queue_name: {"queue": self.queue_name}}
28
- # celery_app.config_from_object(self.broker_exclusive_config)
29
- pass
30
-
31
- # celery_app.conf.task_routes.update({self.queue_name: {"queue": self.queue_name}})
32
- #
33
- # @celery_app.task(name=self.queue_name)
34
- # def f(*args, **kwargs):
35
- # pass
36
- #
37
- # self._celery_app = celery_app
38
- # self._celery_fun = f
39
-
40
- celery_app.conf.task_routes.update({self.queue_name: {"queue": self.queue_name}})
41
19
 
42
20
  def publish(self, msg: typing.Union[str, dict], task_id=None,
43
21
  priority_control_config: PriorityConsumingControlConfig = None) -> celery.result.AsyncResult:
@@ -9,10 +9,11 @@ from threading import Lock
9
9
 
10
10
  from funboost import funboost_config_deafult
11
11
  from funboost.publishers.base_publisher import AbstractPublisher
12
+ from funboost.publishers.redis_queue_flush import FlushRedisQueueMixin
12
13
  from funboost.utils import RedisMixin, decorators
13
14
 
14
15
 
15
- class RedisPublisher(AbstractPublisher, RedisMixin):
16
+ class RedisPublisher(FlushRedisQueueMixin, AbstractPublisher, RedisMixin, ):
16
17
  """
17
18
  使用redis作为中间件,这个是大幅优化了发布速度的方式。简单的发布是 redis_publisher_0000.py 中的代码方式。
18
19
 
@@ -42,7 +43,7 @@ class RedisPublisher(AbstractPublisher, RedisMixin):
42
43
  # print(getattr(frame_config,'has_start_a_consumer_flag',0))
43
44
  # 这里的 has_start_a_consumer_flag 是一个标志,借用此模块设置的一个标识变量而已,框架运行时候自动设定的,不要把这个变量写到模块里面。
44
45
  # if getattr(funboost_config_deafult, 'has_start_a_consumer_flag', 0) == 0: # 加快速度推送,否则每秒只能推送4000次。如果是独立脚本推送,使用批量推送,如果是消费者中发布任务,为了保持原子性,用原来的单个推送。
45
- if self.broker_exclusive_config.get('redis_bulk_push',0) == 1: # RedisConsumer传了, RedisAckAble 没传
46
+ if self.broker_exclusive_config.get('redis_bulk_push', 0) == 1: # RedisConsumer传了, RedisAckAble 没传
46
47
  # self._temp_msg_queue.put(msg)
47
48
  with self._lock_for_bulk_push:
48
49
  self._temp_msg_list.append(msg)
@@ -53,17 +54,6 @@ class RedisPublisher(AbstractPublisher, RedisMixin):
53
54
  getattr(self.redis_db_frame, self._push_method)(self._queue_name, msg)
54
55
  # print(msg)
55
56
 
56
- # self.redis_db_frame.rpush(self._queue_name, msg)
57
- def clear(self):
58
- self.redis_db_frame.delete(self._queue_name)
59
- # self.redis_db_frame.delete(f'{self._queue_name}__unack')
60
- unack_queue_name_list = self.redis_db_frame.scan(match=f'{self._queue_name}__unack_id_*', count=10000)[1] + \
61
- self.redis_db_frame.scan(match=f'unack_{self._queue_name}_*', count=10000)[1] # noqa
62
- self.logger.warning(f'清除 {self._queue_name} 队列中的消息成功')
63
- if unack_queue_name_list:
64
- self.redis_db_frame.delete(*unack_queue_name_list)
65
- self.logger.warning(f'清除 {unack_queue_name_list} 队列中的消息成功')
66
-
67
57
  def get_message_count(self):
68
58
  # print(self.redis_db7,self._queue_name)
69
59
  return self.redis_db_frame.llen(self._queue_name)
@@ -3,10 +3,11 @@
3
3
  # @Time : 2022/8/8 0008 12:12
4
4
 
5
5
  from funboost.publishers.base_publisher import AbstractPublisher
6
+ from funboost.publishers.redis_queue_flush import FlushRedisQueueMixin
6
7
  from funboost.utils.redis_manager import RedisMixin
7
8
 
8
9
 
9
- class RedisPriorityPublisher(AbstractPublisher, RedisMixin):
10
+ class RedisPriorityPublisher(FlushRedisQueueMixin,AbstractPublisher, RedisMixin,):
10
11
  """
11
12
  redis队列,支持任务优先级。
12
13
  """
@@ -39,10 +40,6 @@ class RedisPriorityPublisher(AbstractPublisher, RedisMixin):
39
40
  self.logger.debug([queue_name, msg])
40
41
  self.redis_db_frame.rpush(queue_name, msg)
41
42
 
42
- def clear(self):
43
- self.redis_db_frame.delete(*self.queue_list)
44
- self.redis_db_frame.delete(f'{self._queue_name}__unack')
45
- self.logger.warning(f'清除 {self._queue_name} 队列中的消息成功')
46
43
 
47
44
  def get_message_count(self):
48
45
  count = 0
@@ -2,10 +2,11 @@
2
2
  # @Author : ydf
3
3
  # @Time : 2023/8/8 0008 12:12
4
4
  from funboost.publishers.base_publisher import AbstractPublisher
5
+ from funboost.publishers.redis_queue_flush import FlushRedisQueueMixin
5
6
  from funboost.utils import RedisMixin
6
7
 
7
8
 
8
- class RedisPublisher(AbstractPublisher, RedisMixin):
9
+ class RedisPublisher(FlushRedisQueueMixin, AbstractPublisher, RedisMixin, ):
9
10
  """
10
11
  使用redis作为中间件
11
12
  """
@@ -13,11 +14,6 @@ class RedisPublisher(AbstractPublisher, RedisMixin):
13
14
  def concrete_realization_of_publish(self, msg):
14
15
  self.redis_db_frame.rpush(self._queue_name, msg)
15
16
 
16
- def clear(self):
17
- self.redis_db_frame.delete(self._queue_name)
18
- self.redis_db_frame.delete(f'{self._queue_name}__unack')
19
- self.logger.warning(f'清除 {self._queue_name} 队列中的消息成功')
20
-
21
17
  def get_message_count(self):
22
18
  # nb_print(self.redis_db7,self._queue_name)
23
19
  return self.redis_db_frame.llen(self._queue_name)
@@ -5,7 +5,7 @@ from funboost.publishers.base_publisher import AbstractPublisher
5
5
  from funboost.utils import RedisMixin
6
6
 
7
7
 
8
- class RedisPubSubPublisher(AbstractPublisher, RedisMixin):
8
+ class RedisPubSubPublisher(AbstractPublisher, RedisMixin, ):
9
9
  """
10
10
  使用redis作为中间件
11
11
  """
@@ -0,0 +1,11 @@
1
+ class FlushRedisQueueMixin:
2
+ # noinspection PyUnresolvedReferences
3
+ def clear(self):
4
+ self.redis_db_frame.delete(self._queue_name)
5
+ self.logger.warning(f'清除 {self._queue_name} 队列中的消息成功')
6
+ # self.redis_db_frame.delete(f'{self._queue_name}__unack')
7
+ unack_queue_name_list = self.redis_db_frame.scan(match=f'{self._queue_name}__unack_id_*', count=100000)[1] + \
8
+ self.redis_db_frame.scan(match=f'unack_{self._queue_name}_*', count=100000)[1] # noqa
9
+ if unack_queue_name_list:
10
+ self.redis_db_frame.delete(*unack_queue_name_list)
11
+ self.logger.warning(f'清除 {unack_queue_name_list} 队列中的消息成功')
@@ -14,7 +14,7 @@ class RedisManager(object):
14
14
  if (host, port, db, password) not in self.__class__._pool_dict:
15
15
  # print ('创建一个连接池')
16
16
  self.__class__._pool_dict[(host, port, db, password)] = redis.ConnectionPool(host=host, port=port, db=db,
17
- password=password)
17
+ password=password,max_connections=100)
18
18
  self._r = redis.Redis(connection_pool=self._pool_dict[(host, port, db, password)])
19
19
  self._ping()
20
20
 
@@ -41,7 +41,7 @@ class RedisMixin(object):
41
41
  @decorators.cached_method_result
42
42
  def redis_db0(self):
43
43
  return RedisManager(host=funboost_config_deafult.REDIS_HOST, port=funboost_config_deafult.REDIS_PORT,
44
- password=funboost_config_deafult.REDIS_PASSWORD, db=0).get_redis()
44
+ password=funboost_config_deafult.REDIS_PASSWORD, db=0,).get_redis()
45
45
 
46
46
  @property
47
47
  @decorators.cached_method_result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: funboost
3
- Version: 23.5
3
+ Version: 23.7
4
4
  Summary: pip install funboost,python全功能分布式函数调度框架,。支持python所有类型的并发模式和一切知名消息队列中间件,python函数加速器,框架包罗万象,一统编程思维,兼容50% python业务场景,适用范围广。只需要一行代码即可分布式执行python一切函数,99%用过funboost的pythoner 感受是 方便 快速 强大,相见恨晚
5
5
  Home-page: https://github.com/ydf0509/funboost
6
6
  Author: bfzs
@@ -50,7 +50,7 @@ Requires-Dist: pikav1
50
50
  Requires-Dist: redis2
51
51
  Requires-Dist: redis3
52
52
  Requires-Dist: redis
53
- Requires-Dist: nb-log (>=8.5)
53
+ Requires-Dist: nb-log (>=9.1)
54
54
  Requires-Dist: rocketmq
55
55
  Requires-Dist: zmq
56
56
  Requires-Dist: pyzmq
@@ -159,9 +159,11 @@ funboost 是 function_scheduling_distributed_framework的包名更新版本
159
159
 
160
160
  ## 1.1 安装方式
161
161
 
162
+ ```
162
163
  pip install funboost --upgrade
163
164
 
164
-
165
+ 或pip install funboost[extra_brokers] 一次性安装所有小众三方中间件
166
+ ```
165
167
 
166
168
  ## 1.2 框架功能介绍
167
169
 
@@ -331,6 +333,12 @@ python通用分布式函数调度框架。适用场景范围广泛, 框架非
331
333
  暂停消费:
332
334
  支持从python解释器外部/远程机器 ,控制暂停消息消费和继续消费。
333
335
 
336
+ 优先级队列:
337
+ 支持队列优先级消息。
338
+
339
+ 远程杀死任务:
340
+ 支持在发布端杀死正在运行的消息,发送杀死命令时候对还未取出的消息则放弃运行消息。
341
+
334
342
  </pre>
335
343
 
336
344
 
@@ -1,9 +1,9 @@
1
- funboost/__init__.py,sha256=eBTjiQBcy0DoDZiOdcRJpgb5RHwv8d1ekgVwDkhoHoc,2402
1
+ funboost/__init__.py,sha256=YKM0VVSXRcZJnQbuqkIjS3PnLJxxIjw1-1JjI13Nn3A,2401
2
2
  funboost/__init__old.py,sha256=cSzw-ZQqtAAp5_-7eONXQT5fwz_JbZlRjDQPASDLUHk,20378
3
3
  funboost/constant.py,sha256=tSdHQ8nrZH63jOKKZFtOfTo2melCsiMrk-O1lFcsIKA,6489
4
- funboost/funboost_config_deafult.py,sha256=xpmiZBCVylJe4pC4fG2J-LZZ0c0QJsYXOM1YxQMcMtw,7399
4
+ funboost/funboost_config_deafult.py,sha256=mh9o91CgMC26glIWkw7489GxmJ7bibi4_oBMnv3SCNU,7430
5
5
  funboost/set_frame_config.py,sha256=hz_38C-IXEulYpHQdr1fhsMcdEDCHIsF2la8MkHiIjA,9149
6
- funboost/assist/celery_helper.py,sha256=YvKP21xUzgazZHeFGq4FTgtd0A1g3BGNWzKLQ3gNygc,4186
6
+ funboost/assist/celery_helper.py,sha256=ZJ8jNSC-D8fE6pjxMVGAAA4j9i0gA1kVH14_BbTkXaQ,4569
7
7
  funboost/assist/dramatiq_helper.py,sha256=lRNouO8MyCB_Qj2ppYG4FbMpf-2Aok8QhtGZLH1zWkg,2089
8
8
  funboost/assist/huey_helper.py,sha256=VEzMdQDVJJ-ujcOXKw7chrTgvieLz4si3hrjt8gIK38,1760
9
9
  funboost/assist/rq_helper.py,sha256=-tUZ00FzkczwBAkbbISPHF-8J0K7HLSZsue39WiF-cM,1509
@@ -26,8 +26,8 @@ funboost/concurrent_pool/backup/async_pool_executor0223.py,sha256=iTxxJFk2lu1P9Z
26
26
  funboost/concurrent_pool/backup/async_pool_executor_back.py,sha256=vIgUUyF4Zb0jIRPWgNPqyO09YEkQP32kkpGBldqm4qA,9568
27
27
  funboost/concurrent_pool/backup/async_pool_executor_janus.py,sha256=OHMWJ9l3EYTpPpcrPrGGKd4K0tmQ2PN8HiX0Dta0EOo,5728
28
28
  funboost/consumers/__init__.py,sha256=ZXY_6Kut1VYNQiF5aWEgIWobsW1ht9YUP0TdRZRWFqI,126
29
- funboost/consumers/base_consumer.py,sha256=2wZW7m4i63xf9zfXvsGIp26khTAjMod9-K9828LvbC8,85044
30
- funboost/consumers/celery_consumer.py,sha256=6CqorZH5pbxIjVwn5gNzcxSbos5YWT8eYqxYyYjgUcY,7574
29
+ funboost/consumers/base_consumer.py,sha256=8goq0tx2db0ErfMeuKuNe62K5SOI-4Io58_7-xs2-X8,86846
30
+ funboost/consumers/celery_consumer.py,sha256=l0UQbO_KmvhCLtMtUgoHxHtEqyBCIABykyVKj04lZPM,8815
31
31
  funboost/consumers/celery_consumer000.py,sha256=8SF8ppHIMH-BIAHO0NyJYnSQxe_PcT6hv05e7DySG54,4574
32
32
  funboost/consumers/confirm_mixin.py,sha256=oVBQ1RayIBFOzGNTJ69HdBR_kLd46xd0VfCOKfqDpLA,6033
33
33
  funboost/consumers/dramatiq_consumer.py,sha256=kiHM1wpSZykYDomtSGZ2PlMInCDn_8GOGEHqHUD9m0o,2144
@@ -47,14 +47,14 @@ funboost/consumers/nsq_consumer.py,sha256=PaMRsP8oeRg0H_tq4FL7YhNUdOWAqJkjrwZWoY
47
47
  funboost/consumers/peewee_conusmer.py,sha256=fbspeWbv6F3EsIIBAjkM_FNh2vMyrDsydju23WAVHvE,1238
48
48
  funboost/consumers/persist_queue_consumer.py,sha256=8HzRcMFE6OKiF_CL3atC42Ien_yf5daG3LU38YBKWi0,1005
49
49
  funboost/consumers/pulsar_consumer.py,sha256=2DuklBV5dSY-_gW2EpRWz8QSy-VjZclj0gJUvLTyJHA,2414
50
- funboost/consumers/rabbitmq_amqpstorm_consumer.py,sha256=Qg1Uv4Tk6Tbu9szys6P4U_5BpsOgZuO_kdiR6lb1MlQ,2048
50
+ funboost/consumers/rabbitmq_amqpstorm_consumer.py,sha256=JJnSvewyWJDjAZmBi23r9PYUkt01knHfpRFjpmasjVw,2049
51
51
  funboost/consumers/rabbitmq_pika_consumer.py,sha256=9L7CA2wYT-RNpaVfLKrFk6UJtONEIlfuDZYCjxHDOtc,5433
52
52
  funboost/consumers/rabbitmq_pika_consumerv0.py,sha256=Yr-GJlgtkYB4qx8hKZZRx8PyCGwKAlSvRFKEf-SBXnM,4674
53
53
  funboost/consumers/rabbitmq_rabbitpy_consumer.py,sha256=q-DXy2MHgsFfBssVIlqgziFw2jPkxAT4TyeDnlE0zwI,1260
54
54
  funboost/consumers/redis_brpoplpush_consumer.py,sha256=rVdlmODLEQ8_k-gXFnaMFK8LaiKu3EiZMG2q5jmG8qk,3031
55
55
  funboost/consumers/redis_consumer.py,sha256=f9nASEQUR3VHk5JH5Plf3RqKXmxogfrshu63RaFnfDM,2829
56
- funboost/consumers/redis_consumer_ack_able.py,sha256=DlZd76FTPo-AUiTreQd7cSiT5QAM5K9rFItAwLt2n5Y,7545
57
- funboost/consumers/redis_consumer_priority.py,sha256=avxU89EZuGk-wQeWEpASBU7ustxAHp3KzQcq34wb2Fg,4282
56
+ funboost/consumers/redis_consumer_ack_able.py,sha256=7bdG2282POZ_nbtMK2aAgYi43jNNXbw56uG0eUIII7M,7545
57
+ funboost/consumers/redis_consumer_priority.py,sha256=2BnNvsbNPZCRHdRxrnh1C3mJlqTgb1ql7xRn4-cHULU,5827
58
58
  funboost/consumers/redis_consumer_simple.py,sha256=9D3uvLw_9WOmLmwys1K39DK3gj1ex_q6NXadXwyGwrs,922
59
59
  funboost/consumers/redis_filter.py,sha256=TVyT2i9JhmhsJFyQZDx98phTiwBccNTl9fcErEDGXTM,7135
60
60
  funboost/consumers/redis_pubsub_consumer.py,sha256=eSy5QBMPaouiQbeGQ3ZaLVpU1BF8g3B_4CAJHFqhmmI,1206
@@ -82,6 +82,7 @@ funboost/core/helper_funs.py,sha256=SKSMKytJTOFQJsuMKWJ-_mQg6e_Bgpq1ANDzjjBAcio,
82
82
  funboost/core/kill_remote_task.py,sha256=Rj4nrz13CKka8he1T8-k6CYN_yjvcaYZaZ7yurKcKzo,8159
83
83
  funboost/core/msg_result_getter.py,sha256=a2ffSE8Rvz1t1KVEt4UxIPsWgcriaHE_Armkac-JrJY,7782
84
84
  funboost/core/muliti_process_enhance.py,sha256=zNodv3Ww5yCmwO6xCh7k8HntFHjIYYJ9EPaGinvPV9Q,3814
85
+ funboost/core/show_funboost_flag.py,sha256=EouUN_ioNXWaguA9qKQJKw1xYJqa1aLNxtd9SvL6g8A,5725
85
86
  funboost/factories/__init__.py,sha256=s7kKKjR1HU5eMjPD6r5b-SXTVMo1zBp2JjOAtkyt5Yo,178
86
87
  funboost/factories/broker_kind__publsiher_consumer_type_map.py,sha256=Ig1Kze8keS04_vXMNenZSDxibBSjxVrcMkDHviPsxnQ,8976
87
88
  funboost/factories/consumer_factory.py,sha256=KFvYkx1a7egtSiTLuVsoRMKLUAotx-QJX1jAI8Xzo3s,946
@@ -102,8 +103,8 @@ funboost/function_result_web/static/js/jquery-1.11.0.min.js,sha256=ryQZ3RXgnqkTz
102
103
  funboost/function_result_web/templates/index.html,sha256=dWe-JFQhsDpoNjSsBF4P6SJWp_KvHX8EP_yECS5r7_o,19501
103
104
  funboost/function_result_web/templates/login.html,sha256=q37dj7O0LeyiV38Zd5P1Qn_qmhjdFomuYTRY1Yk48Bo,2007
104
105
  funboost/publishers/__init__.py,sha256=xqBHlvsJQVPfbdvP84G0LHmVB7-pFBS7vDnX1Uo9pVY,131
105
- funboost/publishers/base_publisher.py,sha256=CU0xjCpt1tsQRcy6Orhuxd8bwsmIJ80wmMZw0JDHevY,15860
106
- funboost/publishers/celery_publisher.py,sha256=XCR-xvkHEQhbJSluuhrlMPv-V4RTlpA9Ot10mfe4a3E,3081
106
+ funboost/publishers/base_publisher.py,sha256=uuchEFgHMUlY2fBtGwZFLAzeKiWa7_34UTocGADTt2c,15863
107
+ funboost/publishers/celery_publisher.py,sha256=ELT-JR8RtmmCpsxYqVTuuFeKMFZMuK9ROKXWHkGVEjE,2334
107
108
  funboost/publishers/celery_publisher000.py,sha256=ag2s7MzPPrnNdza3u8vcbDJqtiqbQw4lJJzAVuJ6GF0,3897
108
109
  funboost/publishers/confluent_kafka_publisher.py,sha256=cpbyWvZ0T_kM62LWeBKRUuEuMkJAKOof97UUMSz6-Dk,3541
109
110
  funboost/publishers/dramatiq_publisher.py,sha256=RoZzfvkS5H-XXcmHGBomuvkQRQBlVyiaCdWpgy0LL9o,1410
@@ -124,11 +125,12 @@ funboost/publishers/pulsar_publisher.py,sha256=3BqDtywExvTIw1KZWG4kT1uz029uw2Ykn
124
125
  funboost/publishers/rabbitmq_amqpstorm_publisher.py,sha256=C32sQZpjv1iJtFDD6g_q0wI7Arw9i0RDsRVVOBRKzi4,3137
125
126
  funboost/publishers/rabbitmq_pika_publisher.py,sha256=jZZw3DUiZ4VqJ6FqZGdv7qo3F_ltzHuKsy_5-j4jkCs,2343
126
127
  funboost/publishers/rabbitmq_rabbitpy_publisher.py,sha256=GGXPKxE6-mAjqMIKqwvR9d7L-zuJQcQoU9uRsQLNGas,1953
127
- funboost/publishers/redis_publisher.py,sha256=mUHxfdHYrUn_Dw59NifN-mFsnj53hOhZDoEFlWs-W5M,3982
128
+ funboost/publishers/redis_publisher.py,sha256=FUxvvYvf73J2Im33MRJd-5dmjnccjAFHaTMd4rLvdNM,3358
128
129
  funboost/publishers/redis_publisher_lpush.py,sha256=xEWuCTtbDcKFLTxGrECrbIVapFfUwqX2-GHenMClu-Q,278
129
- funboost/publishers/redis_publisher_priority.py,sha256=zGhSAvpFVBXfAmfGQdWL9cixdpLhLQ6yR3XvBLnbdF4,2104
130
- funboost/publishers/redis_publisher_simple.py,sha256=hLVWiDjy9ObGTmv7Vtrz21d18Fxkb52IfO5ZzaXjzMQ,872
131
- funboost/publishers/redis_pubsub_publisher.py,sha256=_6s7sbcGOSXxN2ZkBSDk9ILskmbj9cZTQyYHLQTYOuI,721
130
+ funboost/publishers/redis_publisher_priority.py,sha256=YJCIMdiY0Sdttc7Xv85V-2P1R7ZoX5hqWz7waoibioQ,1972
131
+ funboost/publishers/redis_publisher_simple.py,sha256=fzEurzFQxrTO6PlCONz4m1jQljwuN66spbj4tIJ3Y6c,740
132
+ funboost/publishers/redis_pubsub_publisher.py,sha256=BxVn31I-Rt6gHFSTqntpsajmsl0ZftgMJMtiZd1LMyA,723
133
+ funboost/publishers/redis_queue_flush.py,sha256=d-AgJiCuX25mOwP2gMorGbXCaLuFpqWO4jAJXJDBfk0,732
132
134
  funboost/publishers/redis_stream_publisher.py,sha256=DLxFcTlze0IdYFoaRmTcY8GCOaRwbj4aBNbylkt9gRA,2037
133
135
  funboost/publishers/rocketmq_publisher.py,sha256=vY82WgutDPsS9px6rukU1d3AexmsT_tqSS2dmX-Pw-c,2343
134
136
  funboost/publishers/rq_publisher.py,sha256=ANHrYnPTEj7KF_D_ov2L7PAT9swl82kjDazFqN1ULBY,893
@@ -158,7 +160,7 @@ funboost/utils/monkey_patches.py,sha256=Q0_jKxOfFrSgrIDSuSZFrgNh6w_LRGaKAITghrIp
158
160
  funboost/utils/mqtt_util.py,sha256=BfCmyYwI-B8VL9499_IuYlJDCbv6ZhwyWThMf8dANOU,3199
159
161
  funboost/utils/paramiko_util.py,sha256=pu67zkgptqNSV9m2Lznezb3zF1AFYvkWJp_6DVKFSPU,4901
160
162
  funboost/utils/rabbitmq_factory.py,sha256=NPzTwG-INZG9aJgkzp-QVk3TgV0rjiuTVT5lmRT77zg,2963
161
- funboost/utils/redis_manager.py,sha256=2Hg9UT-X6nS5TkZ-YrTRxRK-WPHZaLOsuvTxYuD1cCc,4628
163
+ funboost/utils/redis_manager.py,sha256=0mkPxBFE4pBv22Zi9O0YN-txvlRHdpjpl0maW5M0QvM,4649
162
164
  funboost/utils/resource_monitoring.py,sha256=vf1htYa3a4wlMfQqksvIINMw8laiXwG5N8NXU2Zm3qQ,5532
163
165
  funboost/utils/restart_python.py,sha256=bFbV0_24ajL8hBwVRLxWe9v9kTwiX1fGLhXRroNnmgQ,1418
164
166
  funboost/utils/show_funboost_flag.py,sha256=YPXtykSkRBJZ4ulOIAXiTAfpOmo9IsjePz9G9AEE6cg,2985
@@ -213,8 +215,8 @@ funboost/utils/pysnooper_ydf/utils.py,sha256=evSmGi_Oul7vSP47AJ0DLjFwoCYCfunJZ1m
213
215
  funboost/utils/pysnooper_ydf/variables.py,sha256=QejRDESBA06KG9OH4sBT4J1M55eaU29EIHg8K_igaXo,3693
214
216
  funboost/utils/times/__init__.py,sha256=z-KQTxXapfu2ScJxISGe7QGffASuyJYL6JGsLXxD6O0,2332
215
217
  funboost/utils/times/version.py,sha256=JiZLGTB-HYyBOV4xS0rnx2K2OqVMTebUj30sZRbrleE,16
216
- funboost-23.5.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
217
- funboost-23.5.dist-info/METADATA,sha256=vP7DG7GGXW7ktzISGDk4Vsgo-GkvlLpCatSrtc9z9uE,26615
218
- funboost-23.5.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
219
- funboost-23.5.dist-info/top_level.txt,sha256=K8WuKnS6MRcEWxP1NvbmCeujJq6TEfbsB150YROlRw0,9
220
- funboost-23.5.dist-info/RECORD,,
218
+ funboost-23.7.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
219
+ funboost-23.7.dist-info/METADATA,sha256=5MXcCOlQJKBFQo_e0-J6t0Wl3TeNhn2-yFfGl2AR4-I,26928
220
+ funboost-23.7.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
221
+ funboost-23.7.dist-info/top_level.txt,sha256=K8WuKnS6MRcEWxP1NvbmCeujJq6TEfbsB150YROlRw0,9
222
+ funboost-23.7.dist-info/RECORD,,