funboost 44.4__py3-none-any.whl → 44.6__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
@@ -13,7 +13,7 @@ set_frame_config这个模块的 use_config_form_funboost_config_module() 是核
13
13
  这段注释说明和使用的用户无关,只和框架开发人员有关.
14
14
  '''
15
15
 
16
- __version__ = "44.4"
16
+ __version__ = "44.6"
17
17
 
18
18
  from funboost.set_frame_config import show_frame_config
19
19
 
@@ -31,12 +31,13 @@ from funboost.utils.paramiko_util import ParamikoFolderUploader
31
31
 
32
32
  from funboost.consumers.base_consumer import (wait_for_possible_has_finish_all_tasks_by_conusmer_list,
33
33
  FunctionResultStatus, AbstractConsumer)
34
-
34
+ from funboost.consumers.empty_consumer import EmptyConsumer
35
35
  from funboost.core.exceptions import ExceptionForRetry, ExceptionForRequeue, ExceptionForPushToDlxqueue
36
36
  from funboost.core.active_cousumer_info_getter import ActiveCousumerProcessInfoGetter
37
37
  from funboost.core.msg_result_getter import HasNotAsyncResult, ResultFromMongo
38
38
  from funboost.publishers.base_publisher import (PriorityConsumingControlConfig,
39
39
  AbstractPublisher, AsyncResult, AioAsyncResult)
40
+ from funboost.publishers.empty_publisher import EmptyPublisher
40
41
  from funboost.factories.broker_kind__publsiher_consumer_type_map import register_custom_broker
41
42
  from funboost.factories.publisher_factotry import get_publisher
42
43
  from funboost.factories.consumer_factory import get_consumer
funboost/constant.py CHANGED
@@ -1,16 +1,24 @@
1
1
  # coding= utf-8
2
2
  class BrokerEnum:
3
+ EMPTY = 'empty' # 空的实现,需要搭配 boost入参的 consumer_override_cls 和 publisher_override_cls使用,或者被继承。
4
+
3
5
  RABBITMQ_AMQPSTORM = 'RABBITMQ_AMQPSTORM' # 使用 amqpstorm 包操作rabbitmq 作为 分布式消息队列,支持消费确认.强烈推荐这个作为funboost中间件。
4
6
  RABBITMQ = RABBITMQ_AMQPSTORM
5
7
 
6
- RABBITMQ_RABBITPY = 'RABBITMQ_RABBITPY' # 使用 rabbitpy 包操作rabbitmq 作为 分布式消息队列,支持消费确认。
8
+ RABBITMQ_RABBITPY = 'RABBITMQ_RABBITPY' # 使用 rabbitpy 包操作rabbitmq 作为 分布式消息队列,支持消费确认,不建议使用
7
9
 
8
10
  REDIS = 'REDIS' # 使用 redis 的 list结构,brpop 作为分布式消息队列。随意重启和关闭会丢失大量消息,不支持消费确认。注重性能不在乎丢失消息可以选这个redis方案。
11
+ REDIS_ACK_ABLE = 'REDIS_ACK_ABLE' # 基于redis的 list + 临时unack的set队列,采用了 lua脚本操持了取任务和加到pengding为原子性,,基于进程心跳消失判断消息是否为掉线进程的,随意重启和掉线不会丢失任务。
12
+ REIDS_ACK_USING_TIMEOUT = 'reids_ack_using_timeout' # 基于redis的 list + 临时unack的set队列,使用超时多少秒没确认消费就自动重回队列,请注意 ack_timeout的设置值和函数耗时大小,否则会发生反复重回队列的后果,boost可以设置ack超时,broker_exclusive_config={'ack_timeout': 1800}
13
+ REDIS_PRIORITY = 'REDIS_PRIORITY' # # 基于redis的多 list + 临时unack的set队列,blpop监听多个key,和rabbitmq的x-max-priority属性一样,支持任务优先级。看文档4.29优先级队列说明。
14
+ REDIS_STREAM = 'REDIS_STREAM' # 基于redis 5.0 版本以后,使用 stream 数据结构作为分布式消息队列,支持消费确认和持久化和分组消费,是redis官方推荐的消息队列形式,比list结构更适合。
15
+ RedisBrpopLpush = 'RedisBrpopLpush' # 基于redis的list结构但是采用brpoplpush 双队列形式,和 redis_ack_able的实现差不多,实现上采用了原生命令就不需要lua脚本来实现取出和加入unack了。
16
+ REDIS_PUBSUB = 'REDIS_PUBSUB' # 基于redis 发布订阅的,发布一个消息多个消费者都能收到同一条消息,但不支持持久化
9
17
 
10
18
  MEMORY_QUEUE = 'MEMORY_QUEUE' # 使用python queue.Queue实现的基于当前python进程的消息队列,不支持跨进程 跨脚本 跨机器共享任务,不支持持久化,适合一次性短期简单任务。
11
19
  LOCAL_PYTHON_QUEUE = MEMORY_QUEUE # 别名,python本地queue就是基于python自带的语言的queue.Queue,消息存在python程序的内存中,不支持重启断点接续。
12
20
 
13
- RABBITMQ_PIKA = 'RABBITMQ_PIKA' # 使用pika包操作rabbitmq 作为 分布式消息队列。
21
+ RABBITMQ_PIKA = 'RABBITMQ_PIKA' # 使用pika包操作rabbitmq 作为 分布式消息队列。,不建议使用
14
22
 
15
23
  MONGOMQ = 'MONGOMQ' # 使用mongo的表中的行模拟的 作为分布式消息队列,支持消费确认。
16
24
 
@@ -27,19 +35,13 @@ class BrokerEnum:
27
35
 
28
36
  KAFKA_CONFLUENT_SASlPlAIN = 'KAFKA_CONFLUENT_SASlPlAIN' # 可以设置账号密码的kafka
29
37
 
30
- REDIS_ACK_ABLE = 'REDIS_ACK_ABLE' # 基于redis的 list + 临时unack的set队列,采用了 lua脚本操持了取任务和加到pengding为原子性,随意重启和掉线不会丢失任务。
31
-
32
- REDIS_PRIORITY = 'REDIS_PRIORITY' # # 基于redis的多 list + 临时unack的set队列,blpop监听多个key,和rabbitmq的x-max-priority属性一样,支持任务优先级。看文档4.29优先级队列说明。
33
-
34
38
  SQLACHEMY = 'SQLACHEMY' # 基于SQLACHEMY 的连接作为分布式消息队列中间件支持持久化和消费确认。支持mysql oracle sqlserver等5种数据库。
35
39
 
36
40
  ROCKETMQ = 'ROCKETMQ' # 基于 rocketmq 作为分布式消息队列,这个中间件必须在linux下运行,win不支持。
37
41
 
38
- REDIS_STREAM = 'REDIS_STREAM' # 基于redis 5.0 版本以后,使用 stream 数据结构作为分布式消息队列,支持消费确认和持久化和分组消费,是redis官方推荐的消息队列形式,比list结构更适合。
39
-
40
42
  ZEROMQ = 'ZEROMQ' # 基于zeromq作为分布式消息队列,不需要安装中间件,可以支持跨机器但不支持持久化。
41
43
 
42
- RedisBrpopLpush = 'RedisBrpopLpush' # 基于redis的list结构但是采用brpoplpush 双队列形式,和 redis_ack_able的实现差不多,实现上采用了原生命令就不需要lua脚本来实现取出和加入unack了。
44
+
43
45
 
44
46
  """
45
47
  操作 kombu 包,这个包也是celery的中间件依赖包,这个包可以操作10种中间件(例如rabbitmq redis),但没包括分布式函数调度框架的kafka nsq zeromq 等。
@@ -69,7 +71,6 @@ class BrokerEnum:
69
71
 
70
72
  PEEWEE = 'PEEWEE' # peewee包操作mysql,使用表模拟消息队列
71
73
 
72
- REDIS_PUBSUB = 'REDIS_PUBSUB' # 基于redis 发布订阅的,发布一个消息多个消费者都能收到同一条消息,但不支持持久化
73
74
 
74
75
  CELERY = 'CELERY' # funboost支持celery框架来发布和消费任务,由celery框架来调度执行任务,但是写法简单远远暴击用户亲自使用celery的麻烦程度,
75
76
  # 用户永无无需关心和操作Celery对象实例,无需关心celery的task_routes和include配置,funboost来自动化设置这些celery配置。
@@ -35,6 +35,7 @@ from funboost.core.loggers import develop_logger
35
35
 
36
36
  from funboost.core.func_params_model import BoosterParams, PublisherParams, BaseJsonAbleModel
37
37
  from funboost.core.task_id_logger import TaskIdLogger
38
+ from funboost.utils.json_helper import JsonUtils
38
39
  from nb_log import (get_logger, LoggerLevelSetterMixin, LogManager, is_main_process,
39
40
  nb_log_config_default)
40
41
  from funboost.core.loggers import FunboostFileLoggerMixin, logger_prompt
@@ -428,8 +429,8 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
428
429
  self._last_show_pause_log_time = time.time()
429
430
  else:
430
431
  break
431
- self._print_message_get_from_broker(kw['body'])
432
432
  kw['body'] = self.convert_msg_before_run(kw['body'])
433
+ self._print_message_get_from_broker(kw['body'])
433
434
  if self._judge_is_daylight():
434
435
  self._requeue(kw)
435
436
  time.sleep(self.time_interval_for_check_do_not_run_time)
@@ -531,10 +532,8 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
531
532
  def _print_message_get_from_broker(self, msg, broker_name=None):
532
533
  # print(999)
533
534
  if self.consumer_params.is_show_message_get_from_broker:
534
- if isinstance(msg, (dict, list)):
535
- msg = json.dumps(msg, ensure_ascii=False)
536
535
  # self.logger.debug(f'从 {broker_name} 中间件 的 {self._queue_name} 中取出的消息是 {msg}')
537
- self.logger.debug(f'从 {broker_name or self.consumer_params.broker_kind} 中间件 的 {self._queue_name} 中取出的消息是 {msg}')
536
+ self.logger.debug(f'从 {broker_name or self.consumer_params.broker_kind} 中间件 的 {self._queue_name} 中取出的消息是 {JsonUtils.to_json_str(msg)}')
538
537
 
539
538
  def _get_priority_conf(self, kw: dict, broker_task_config_key: str):
540
539
  broker_task_config = kw['body'].get('extra', {}).get(broker_task_config_key, None)
@@ -563,6 +562,9 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
563
562
  """
564
563
  self._do_not_delete_extra_from_msg = True
565
564
 
565
+ def user_custom_record_process_info_func(self,current_function_result_status:FunctionResultStatus): # 这个可以继承
566
+ pass
567
+
566
568
  # noinspection PyProtectedMember
567
569
  def _run(self, kw: dict, ):
568
570
  # print(kw)
@@ -634,7 +636,7 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
634
636
  self._current_time_for_execute_task_times_every_unit_time = time.time()
635
637
  self._consuming_function_cost_time_total_every_unit_time = 0
636
638
  self._execute_task_times_every_unit_time = 0
637
-
639
+ self.user_custom_record_process_info_func(current_function_result_status) # 两种方式都可以自定义,记录结果.
638
640
  if self.consumer_params.user_custom_record_process_info_func:
639
641
  self.consumer_params.user_custom_record_process_info_func(current_function_result_status)
640
642
  except BaseException as e:
@@ -0,0 +1,26 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Author : ydf
3
+ # @Time : 2023/8/8 0008 13:32
4
+
5
+ import abc
6
+ from funboost.consumers.base_consumer import AbstractConsumer
7
+
8
+
9
+ class EmptyConsumer(AbstractConsumer, metaclass=abc.ABCMeta):
10
+ """
11
+ 空的消费者没实现,空的实现,需要搭配 boost入参的 consumer_override_cls 和 publisher_override_cls使用,或者被继承。
12
+ """
13
+ def custom_init(self):
14
+ pass
15
+
16
+ @abc.abstractmethod
17
+ def _shedual_task(self):
18
+ raise NotImplemented('not realization')
19
+
20
+ @abc.abstractmethod
21
+ def _confirm_consume(self, kw):
22
+ raise NotImplemented('not realization')
23
+
24
+ @abc.abstractmethod
25
+ def _requeue(self, kw):
26
+ raise NotImplemented('not realization')
@@ -17,20 +17,20 @@ class RedisConsumer(AbstractConsumer, RedisMixin):
17
17
  redis作为中间件实现的,使用redis list 结构实现的。
18
18
  这个如果消费脚本在运行时候随意反复重启或者非正常关闭或者消费宕机,会丢失大批任务。高可靠需要用rabbitmq或者redis_ack_able或者redis_stream的中间件方式。
19
19
 
20
- 这个是复杂版,一次性拉取100个,简单版在 funboost/consumers/redis_consumer_simple.py
20
+ 这个是复杂版,一次性拉取100个,减少和redis的交互,简单版在 funboost/consumers/redis_consumer_simple.py
21
21
  """
22
22
 
23
- BROKER_EXCLUSIVE_CONFIG_DEFAULT = {'redis_bulk_push':1} #redis_bulk_push 是否redis批量推送
23
+ BROKER_EXCLUSIVE_CONFIG_DEFAULT = {'redis_bulk_push':1,'pull_msg_batch_size':100} #redis_bulk_push 是否redis批量推送
24
24
 
25
25
  # noinspection DuplicatedCode
26
26
  def _shedual_task(self):
27
+ pull_msg_batch_size = self.consumer_params.broker_exclusive_config['pull_msg_batch_size']
27
28
  while True:
28
29
  # if False:
29
30
  # pass
30
31
  with self.redis_db_frame.pipeline() as p:
31
- get_msg_batch_size = 100
32
- p.lrange(self._queue_name, 0, get_msg_batch_size - 1)
33
- p.ltrim(self._queue_name, get_msg_batch_size, -1)
32
+ p.lrange(self._queue_name, 0, pull_msg_batch_size- 1)
33
+ p.ltrim(self._queue_name, pull_msg_batch_size, -1)
34
34
  task_str_list = p.execute()[0]
35
35
  if task_str_list:
36
36
  # self.logger.debug(f'从redis的 [{self._queue_name}] 队列中 取出的消息是: {task_str_list} ')
@@ -99,6 +99,7 @@ class RedisConsumerAckAble(ConsumerConfirmMixinWithTheHelpOfRedisByHearbeat, Abs
99
99
  # print(script_4(keys=["text_pipelien1","text_pipelien1b"]))
100
100
  """
101
101
 
102
+ BROKER_EXCLUSIVE_CONFIG_DEFAULT = { 'pull_msg_batch_size': 100}
102
103
 
103
104
  def _shedual_task000(self):
104
105
  # 可以采用lua脚本,也可以采用redis的watch配合pipeline使用。比代码分两行pop和zadd比还能减少一次io交互,还能防止丢失小概率一个任务。
@@ -122,8 +123,9 @@ class RedisConsumerAckAble(ConsumerConfirmMixinWithTheHelpOfRedisByHearbeat, Abs
122
123
  time.sleep(0.5)
123
124
 
124
125
  def _shedual_task(self):
125
- lua = '''
126
- local task_list = redis.call("lrange", KEYS[1],0,99)
126
+ pull_msg_batch_size = self.consumer_params.broker_exclusive_config['pull_msg_batch_size']
127
+ lua = f'''
128
+ local task_list = redis.call("lrange", KEYS[1],0,{pull_msg_batch_size-1})
127
129
  redis.call("ltrim", KEYS[1],100,-1)
128
130
  if (#task_list > 0) then
129
131
  for task_index,task_value in ipairs(task_list)
@@ -0,0 +1,77 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Author : ydf
3
+ # @Time : 2024/8/8 0008 13:32
4
+ import json
5
+ import time
6
+ from funboost.consumers.base_consumer import AbstractConsumer
7
+ from funboost.utils.decorators import RedisDistributedLockContextManager
8
+ from funboost.utils.json_helper import JsonUtils
9
+ from funboost.utils.redis_manager import RedisMixin
10
+
11
+
12
+ class RedisConsumerAckUsingTimeout(AbstractConsumer, RedisMixin):
13
+ """
14
+ redis作为中间件实现的。
15
+ 使用超时未能ack就自动重入消息队列,例如消息取出后,由于突然断电或重启或其他原因,导致消息以后再也不能主动ack了,超过一定时间就重新放入消息队列
16
+ """
17
+
18
+ BROKER_EXCLUSIVE_CONFIG_DEFAULT = {'ack_timeout': 3600}
19
+
20
+ # RedisConsumerAckUsingTimeout的ack timeot 是代表消息取出后过了多少秒还未ack,就自动重回队列。这个配置一定要大于函数消耗时间,否则不停的重回队列。
21
+ '''用法,如何设置ack_timeout,是使用 broker_exclusive_config 中传递,就能覆盖这里的3600,用户不用改BROKER_EXCLUSIVE_CONFIG_DEFAULT的源码。
22
+ @boost(BoosterParams(queue_name='test_redis_ack__use_timeout', broker_kind=BrokerEnum.REIDS_ACK_USING_TIMEOUT,
23
+ concurrent_num=5, log_level=20, broker_exclusive_config={'ack_timeout': 30}))
24
+ '''
25
+
26
+ def custom_init(self):
27
+ self._unack_zset_name = f'{self._queue_name}__unack_using_timeout'
28
+ self._ack_timeout = self.consumer_params.broker_exclusive_config['ack_timeout']
29
+ self._last_show_unack_ts = time.time()
30
+
31
+ def start_consuming_message(self):
32
+ self._is_send_consumer_hearbeat_to_redis = True
33
+ super().start_consuming_message()
34
+ self.keep_circulating(10, block=False)(self._requeue_tasks_which_unconfirmed)()
35
+
36
+ # def _add_task_str_to_unack_zset(self, task_str, ):
37
+ # self.redis_db_frame.zadd(self._unack_zset_name, {task_str: time.time()})
38
+
39
+ def _confirm_consume(self, kw):
40
+ self.redis_db_frame.zrem(self._unack_zset_name, kw['task_str'])
41
+
42
+ def _requeue(self, kw):
43
+ self.redis_db_frame.rpush(self._queue_name, JsonUtils.to_json_str(kw['body']))
44
+
45
+ def _shedual_task(self):
46
+ lua = '''
47
+ local v = redis.call("lpop", KEYS[1])
48
+ if v then
49
+ redis.call('zadd',KEYS[2],ARGV[1],v)
50
+ end
51
+ return v
52
+ '''
53
+ script = self.redis_db_frame.register_script(lua)
54
+ while True:
55
+ return_v = script(keys=[self._queue_name, self._unack_zset_name], args=[time.time()])
56
+ if return_v:
57
+ task_str = return_v
58
+ kw = {'body': task_str, 'task_str': task_str}
59
+ self._submit_task(kw)
60
+ else:
61
+ time.sleep(0.1)
62
+
63
+ def _requeue_tasks_which_unconfirmed(self):
64
+ """不使用这种方案,不适合本来来就需要长耗时的函数,很死板"""
65
+ # 防止在多个进程或多个机器中同时做扫描和放入未确认消费的任务。使用个分布式锁。
66
+ lock_key = f'funboost_lock__requeue_tasks_which_unconfirmed_timeout:{self._queue_name}'
67
+ with RedisDistributedLockContextManager(self.redis_db_frame, lock_key, ) as lock:
68
+ if lock.has_aquire_lock:
69
+ time_max = time.time() - self._ack_timeout
70
+ for value in self.redis_db_frame.zrangebyscore(self._unack_zset_name, 0, time_max):
71
+ self.logger.warning(f'超过了 {self._ack_timeout} 秒未能确认消费, 向 {self._queue_name} 队列重新放入未消费确认的任务 {value} ,')
72
+ self._requeue({'body': value})
73
+ self.redis_db_frame.zrem(self._unack_zset_name, value)
74
+ if time.time() - self._last_show_unack_ts > 600: # 不要频繁提示打扰
75
+ self.logger.info(f'{self._unack_zset_name} 中有待确认消费任务的数量是'
76
+ f' {self.redis_db_frame.zcard(self._unack_zset_name)}')
77
+ self._last_show_unack_ts = time.time()
@@ -17,7 +17,6 @@ class RedisConsumer(AbstractConsumer, RedisMixin):
17
17
  while True:
18
18
  result = self.redis_db_frame.blpop(self._queue_name,timeout=60)
19
19
  if result:
20
-
21
20
  kw = {'body': result[1]}
22
21
  self._submit_task(kw)
23
22
 
@@ -14,7 +14,7 @@ class RedisStreamConsumer(AbstractConsumer, RedisMixin):
14
14
  redis 的 stream 结构 作为中间件实现的。需要redis 5.0以上,redis stream结构 是redis的消息队列,概念类似kafka,功能远超 list结构。
15
15
  """
16
16
  GROUP = 'funboost_group'
17
- BROKER_EXCLUSIVE_CONFIG_DEFAULT = {'group': 'funboost_group'}
17
+ BROKER_EXCLUSIVE_CONFIG_DEFAULT = {'group': 'funboost_group','pull_msg_batch_size': 100}
18
18
 
19
19
  def custom_init(self):
20
20
  self.group = self.consumer_params.broker_exclusive_config['group'] or self.GROUP
@@ -33,6 +33,7 @@ class RedisStreamConsumer(AbstractConsumer, RedisMixin):
33
33
  self.keep_circulating(60, block=False)(self._requeue_tasks_which_unconfirmed)()
34
34
 
35
35
  def _shedual_task(self):
36
+ pull_msg_batch_size = self.consumer_params.broker_exclusive_config['pull_msg_batch_size']
36
37
 
37
38
  try:
38
39
  self.redis_db_frame.xgroup_create(self._queue_name,self.group , id=0, mkstream=True)
@@ -41,7 +42,7 @@ class RedisStreamConsumer(AbstractConsumer, RedisMixin):
41
42
  while True:
42
43
  # redis服务端必须是5.0以上,并且确保这个键的类型是stream不能是list数据结构。
43
44
  results = self.redis_db_frame.xreadgroup(self.group, self.consumer_identification,
44
- {self.queue_name: ">"}, count=100, block=60 * 1000)
45
+ {self.queue_name: ">"}, count=pull_msg_batch_size, block=60 * 1000)
45
46
  if results:
46
47
  # self.logger.debug(f'从redis的 [{self._queue_name}] stream 中 取出的消息是: {results} ')
47
48
  self._print_message_get_from_broker( results)
@@ -1,7 +1,7 @@
1
1
  import traceback
2
2
  import typing
3
3
 
4
- from funboost import AioAsyncResult, AsyncResult
4
+ from funboost import AioAsyncResult, AsyncResult,PriorityConsumingControlConfig
5
5
 
6
6
  from funboost.core.cli.discovery_boosters import BoosterDiscovery
7
7
  from funboost import BoostersManager
@@ -39,11 +39,12 @@ async def publish_msg(msg_item: MsgItem):
39
39
  if msg_item.need_result:
40
40
  if booster.boost_params.is_using_rpc_mode is False:
41
41
  raise ValueError(f' need_result 为true,{booster.queue_name} 队列消费者 需要@boost设置支持rpc模式')
42
- async_result = booster.publish(msg_item.msg_body)
42
+ async_result = await booster.aio_publish(msg_item.msg_body,priority_control_config=PriorityConsumingControlConfig(is_using_rpc_mode=True))
43
43
  status_and_result = await AioAsyncResult(async_result.task_id, timeout=msg_item.timeout).status_and_result
44
+ print(status_and_result)
44
45
  # status_and_result = AsyncResult(async_result.task_id, timeout=msg_item.timeout).status_and_result
45
46
  else:
46
- booster.publish(msg_item.msg_body)
47
+ await booster.aio_publish(msg_item.msg_body)
47
48
  return PublishResponse(succ=True, msg=f'{msg_item.queue_name} 队列,消息发布成功', status_and_result=status_and_result)
48
49
  except Exception as e:
49
50
  return PublishResponse(succ=False, msg=f'{msg_item.queue_name} 队列,消息发布失败 {type(e)} {e} {traceback.format_exc()}',
@@ -0,0 +1,12 @@
1
+ # import threading
2
+ #
3
+ # from funboost.core.current_task import thread_current_task
4
+ #
5
+ #
6
+ # class FctThread(threading.Thread):
7
+ # thread_current_task__dict_key = 'thread_current_task__dict'
8
+ #
9
+ #
10
+ # def run(self):
11
+ # thread_current_task._fct_local_data.__dict__.update(getattr(self,self.thread_current_task__dict_key)) # 把funboost的消费线程上下文需要传递到线程上下文里面来.
12
+ # super().run()
@@ -178,13 +178,16 @@ class BoosterParams(BaseJsonAbleModel):
178
178
 
179
179
  consuming_function: typing.Callable = None # 消费函数,在@boost时候不用指定,因为装饰器知道下面的函数.
180
180
 
181
- broker_kind: str = BrokerEnum.PERSISTQUEUE # 中间件选型见3.1章节 https://funboost.readthedocs.io/zh/latest/articles/c3.html
181
+ broker_kind: str = BrokerEnum.SQLITE_QUEUE # 中间件选型见3.1章节 https://funboost.readthedocs.io/zh/latest/articles/c3.html
182
182
 
183
183
  broker_exclusive_config: dict = {} # 加上一个不同种类中间件非通用的配置,不同中间件自身独有的配置,不是所有中间件都兼容的配置,因为框架支持30种消息队列,消息队列不仅仅是一般的先进先出queue这么简单的概念,
184
184
  # 例如kafka支持消费者组,rabbitmq也支持各种独特概念例如各种ack机制 复杂路由机制,有的中间件原生能支持消息优先级有的中间件不支持,每一种消息队列都有独特的配置参数意义,可以通过这里传递。每种中间件能传递的键值对可以看consumer类的 BROKER_EXCLUSIVE_CONFIG_DEFAULT
185
185
 
186
186
  should_check_publish_func_params: bool = True # 消息发布时候是否校验消息发布内容,比如有的人发布消息,函数只接受a,b两个入参,他去传2个入参,或者传参不存在的参数名字, 如果消费函数你非要写*args,**kwargs,那就需要关掉发布消息时候的函数入参检查
187
187
 
188
+ consumer_override_cls: typing.Optional[typing.Type] = None # 使用 consumer_override_cls 和 publisher_override_cls 来自定义重写或新增消费者 发布者,见文档4.21b介绍,
189
+ publisher_override_cls: typing.Optional[typing.Type] = None
190
+
188
191
  auto_generate_info: dict = {} # 自动生成的信息,不需要用户主动传参.
189
192
 
190
193
  @root_validator(skip_on_failure=True)
@@ -266,6 +269,7 @@ class PublisherParams(BaseJsonAbleModel):
266
269
  broker_kind: str = None
267
270
  broker_exclusive_config: dict = {}
268
271
  should_check_publish_func_params: bool = True # 消息发布时候是否校验消息发布内容,比如有的人发布消息,函数只接受a,b两个入参,他去传2个入参,或者传参不存在的参数名字, 如果消费函数你非要写*args,**kwargs,那就需要关掉发布消息时候的函数入参检查
272
+ publisher_override_cls: typing.Optional[typing.Type] = None
269
273
 
270
274
 
271
275
  if __name__ == '__main__':
@@ -277,4 +281,4 @@ if __name__ == '__main__':
277
281
  # print(PriorityConsumingControlConfig().get_str_dict())
278
282
 
279
283
  print(BoosterParams(queue_name='3213', specify_concurrent_pool=FlexibleThreadPool(100)).json_pre())
280
- print(PublisherParams.schema_json())
284
+ print(PublisherParams.schema_json())
@@ -1,5 +1,6 @@
1
1
  import typing
2
2
 
3
+ from funboost.publishers.empty_publisher import EmptyPublisher
3
4
  from funboost.publishers.http_publisher import HTTPPublisher
4
5
  from funboost.publishers.nats_publisher import NatsPublisher
5
6
  from funboost.publishers.peewee_publisher import PeeweePublisher
@@ -24,6 +25,7 @@ from funboost.publishers.redis_stream_publisher import RedisStreamPublisher
24
25
  from funboost.publishers.mqtt_publisher import MqttPublisher
25
26
  from funboost.publishers.httpsqs_publisher import HttpsqsPublisher
26
27
 
28
+ from funboost.consumers.empty_consumer import EmptyConsumer
27
29
  from funboost.consumers.redis_consumer_priority import RedisPriorityConsumer
28
30
  from funboost.consumers.redis_pubsub_consumer import RedisPbSubConsumer
29
31
  from funboost.consumers.http_consumer import HTTPConsumer
@@ -48,6 +50,7 @@ from funboost.consumers.udp_consumer import UDPConsumer
48
50
  from funboost.consumers.zeromq_consumer import ZeroMqConsumer
49
51
  from funboost.consumers.mqtt_consumer import MqttConsumer
50
52
  from funboost.consumers.httpsqs_consumer import HttpsqsConsumer
53
+ from funboost.consumers.redis_consumer_ack_using_timeout import RedisConsumerAckUsingTimeout
51
54
 
52
55
  from funboost.publishers.base_publisher import AbstractPublisher
53
56
  from funboost.consumers.base_consumer import AbstractConsumer
@@ -77,6 +80,8 @@ broker_kind__publsiher_consumer_type_map = {
77
80
  BrokerEnum.TXT_FILE: (TxtFilePublisher, TxtFileConsumer),
78
81
  BrokerEnum.PEEWEE: (PeeweePublisher, PeeweeConsumer),
79
82
  BrokerEnum.REDIS_PUBSUB: (RedisPubSubPublisher, RedisPbSubConsumer),
83
+ BrokerEnum.REIDS_ACK_USING_TIMEOUT: (RedisPublisher, RedisConsumerAckUsingTimeout),
84
+ BrokerEnum.EMPTY:(EmptyPublisher,EmptyConsumer),
80
85
 
81
86
  }
82
87
 
@@ -163,8 +168,6 @@ def regist_to_funboost(broker_kind: str):
163
168
  register_custom_broker(broker_kind, NsqPublisher, NsqConsumer)
164
169
 
165
170
 
166
-
167
-
168
171
  if __name__ == '__main__':
169
172
  import sys
170
173
 
@@ -20,4 +20,12 @@ def get_consumer(boost_params: BoosterParams) -> AbstractConsumer:
20
20
 
21
21
  if boost_params.broker_kind not in broker_kind__publsiher_consumer_type_map:
22
22
  raise ValueError(f'设置的中间件种类数字不正确,你设置的值是 {boost_params.broker_kind} ')
23
- return broker_kind__publsiher_consumer_type_map[boost_params.broker_kind][1](boost_params)
23
+ consumer_cls = broker_kind__publsiher_consumer_type_map[boost_params.broker_kind][1]
24
+ if not boost_params.consumer_override_cls:
25
+ return consumer_cls(boost_params)
26
+ else:
27
+ ConsumerClsOverride = type(f'{consumer_cls.__name__}__{boost_params.consumer_override_cls.__name__}', (boost_params.consumer_override_cls, consumer_cls, AbstractConsumer), {})
28
+ # class ConsumerClsOverride(boost_params.consumer_override_cls, consumer_cls, AbstractConsumer):
29
+ # pass
30
+
31
+ return ConsumerClsOverride(boost_params)
@@ -32,4 +32,13 @@ def get_publisher(publisher_params: PublisherParams) -> AbstractPublisher:
32
32
  regist_to_funboost(broker_kind) # 动态注册中间件到框架是为了延迟导入,用户没安装不需要的第三方包不报错。
33
33
  if broker_kind not in broker_kind__publsiher_consumer_type_map:
34
34
  raise ValueError(f'设置的中间件种类数字不正确,你设置的值是 {broker_kind} ')
35
- return broker_kind__publsiher_consumer_type_map[broker_kind][0](publisher_params)
35
+ publisher_cls = broker_kind__publsiher_consumer_type_map[broker_kind][0]
36
+ if not publisher_params.publisher_override_cls:
37
+ return publisher_cls(publisher_params)
38
+ else:
39
+ PublsiherClsOverride = type(f'{publisher_cls.__name__}__{publisher_params.publisher_override_cls.__name__}', (publisher_params.publisher_override_cls, publisher_cls, AbstractPublisher), {})
40
+ # class PublsiherClsOverride(publisher_params.publisher_override_cls, publisher_cls, AbstractPublisher):
41
+ # pass
42
+
43
+ return PublsiherClsOverride(publisher_params)
44
+
@@ -0,0 +1,31 @@
1
+ # -*- coding: utf-8 -*-
2
+ # @Author : ydf
3
+ # @Time : 2023/8/8 0008 12:12
4
+
5
+ import abc
6
+ from funboost.publishers.base_publisher import AbstractPublisher
7
+
8
+
9
+ class EmptyPublisher(AbstractPublisher, metaclass=abc.ABCMeta):
10
+ """
11
+ 空的发布者,空的实现,需要搭配 boost入参的 consumer_override_cls 和 publisher_override_cls使用,或者被继承。
12
+ """
13
+
14
+ def custom_init(self):
15
+ pass
16
+
17
+ @abc.abstractmethod
18
+ def concrete_realization_of_publish(self, msg: str):
19
+ raise NotImplemented('not realization')
20
+
21
+ @abc.abstractmethod
22
+ def clear(self):
23
+ raise NotImplemented('not realization')
24
+
25
+ @abc.abstractmethod
26
+ def get_message_count(self):
27
+ raise NotImplemented('not realization')
28
+
29
+ @abc.abstractmethod
30
+ def close(self):
31
+ raise NotImplemented('not realization')
@@ -98,7 +98,7 @@ def show_frame_config():
98
98
  # only_print_on_main_process(f'{var_name}: {var_value[0]}{"*" * (len(var_value) - 2)}{var_value[-1]}')
99
99
  # else:
100
100
  # only_print_on_main_process(f'{var_name}: {var_value}')
101
- logger_prompt.debug(f'''读取的 BrokerConnConfig 配置是:\n {funboost_config_deafult.BrokerConnConfig().get_json(indent=None)} ''')
101
+ logger_prompt.debug(f'''读取的 BrokerConnConfig 配置是:\n {funboost_config_deafult.BrokerConnConfig().get_pwd_enc_json(indent=4)} ''')
102
102
 
103
103
  logger_prompt.debug(f'''读取的 FunboostCommonConfig 配置是:\n {funboost_config_deafult.FunboostCommonConfig().get_json(indent=None)} ''')
104
104
 
@@ -0,0 +1,51 @@
1
+ #
2
+ #
3
+ # # def get_child_custom_attr(child_cls:type,):
4
+ # # __dict = child_cls.__dict__
5
+ #
6
+ # def merge_cls(cls1:type,cls2:type):
7
+ # class Cls(cls2):
8
+ # pass
9
+ # for k,v in cls1.__dict__.items():
10
+ # if k.startswith('__') and k.endswith('__'):
11
+ # continue
12
+ # print(k,v)
13
+ # setattr(Cls,k,v)
14
+ # return Cls
15
+ #
16
+ #
17
+ # if __name__ == '__main__':
18
+ # class Parent:
19
+ # attr1=1
20
+ # def method_from_parent(self):
21
+ # print('method_from_parent')
22
+ #
23
+ # def method_from_parent2(self):
24
+ # print('method_from_parent2')
25
+ #
26
+ #
27
+ # class Child(Parent):
28
+ # attr1=2
29
+ # attr2=22
30
+ #
31
+ # def method_from_parent2(self):
32
+ # print('method_from_parent2chile')
33
+ # def method_from_child(self:Parent):
34
+ # print('method_from_child')
35
+ #
36
+ # class Child2(Parent,Parent):
37
+ # attr1 = 3
38
+ #
39
+ # class Child2b(Child2):
40
+ # attr1 = '2b'
41
+ #
42
+ #
43
+ # class Child2New(Child2b,Child):
44
+ # pass
45
+ #
46
+ #
47
+ # print(Child2().method_from_parent2())
48
+ # print(Child2New().method_from_parent2())
49
+ #
50
+ #
51
+ #
@@ -332,6 +332,7 @@ class RedisDistributedLockContextManager(LoggerMixin, LoggerLevelSetterMixin):
332
332
  self._expire_seconds = expire_seconds
333
333
  self.identifier = str(uuid.uuid4())
334
334
  self.has_aquire_lock = False
335
+ self.logger.setLevel(logging.INFO)
335
336
 
336
337
  def __enter__(self):
337
338
  self._line = sys._getframe().f_back.f_lineno # 调用此方法的代码的函数
@@ -508,7 +509,7 @@ def cached_method_result_for_instance(fun):
508
509
 
509
510
 
510
511
  class FunctionResultCacher:
511
- logger = LogManager('FunctionResultChche').get_logger_and_add_handlers()
512
+ logger = LogManager('FunctionResultChche').get_logger_and_add_handlers(log_level_int=20)
512
513
  func_result_dict = {}
513
514
  """
514
515
  {
@@ -1,4 +1,5 @@
1
1
  import json
2
+ import typing
2
3
  from datetime import datetime as _datetime
3
4
  from datetime import date as _date
4
5
 
@@ -44,8 +45,20 @@ def monkey_patch_json():
44
45
  json.dumps = _dumps
45
46
 
46
47
 
48
+ class JsonUtils:
49
+ @staticmethod
50
+ def to_dict(obj:typing.Union[str,dict,list]):
51
+ if isinstance(obj,str):
52
+ return json.loads(obj)
53
+ else:
54
+ return obj
47
55
 
48
-
56
+ @staticmethod
57
+ def to_json_str(obj:typing.Union[str,dict,list]):
58
+ if isinstance(obj,str):
59
+ return obj
60
+ else:
61
+ return json.dumps(obj,ensure_ascii=False)
49
62
 
50
63
  if __name__ == '__main__':
51
64
  pass
@@ -1,7 +1,10 @@
1
+ import json
2
+
1
3
  import copy
2
4
  import typing
3
5
 
4
6
  from funboost.utils import json_helper
7
+ from funboost.utils.str_utils import PwdEnc, StrHelper
5
8
 
6
9
 
7
10
  class DataClassBase:
@@ -34,6 +37,20 @@ class DataClassBase:
34
37
  def get_json(self,indent=4):
35
38
  return json_helper.dict_to_un_strict_json(self.get_dict(),indent=indent)
36
39
 
40
+ def get_pwd_enc_json(self,indent=4):
41
+ """防止打印密码明文,泄漏密码"""
42
+ dict_new = {}
43
+ for k, v in self.get_dict().items():
44
+ # only_print_on_main_process(f'{k} : {v}')
45
+ if isinstance(v, (bool, tuple, dict, float, int)):
46
+ dict_new[k] = v
47
+ else:
48
+ v_enc =PwdEnc.enc_broker_uri(str(v))
49
+ if StrHelper(k).judge_contains_str_list(['pwd', 'pass_word', 'password', 'passwd', 'pass']):
50
+ v_enc = PwdEnc.enc_pwd(v_enc)
51
+ dict_new[k] = v_enc
52
+ return json.dumps(dict_new, ensure_ascii=False, indent=indent)
53
+
37
54
  @classmethod
38
55
  def update_cls_attribute(cls,**kwargs):
39
56
  for k ,v in kwargs.items():
@@ -0,0 +1,51 @@
1
+ import re
2
+
3
+
4
+ class PwdEnc:
5
+
6
+ @classmethod
7
+ def enc_broker_uri(cls, uri: str):
8
+ protocol_split_list = uri.split('://')
9
+ if len(protocol_split_list) != 2:
10
+ return uri
11
+ user_pass__ip_port_split_list = protocol_split_list[1].split('@')
12
+ if len(user_pass__ip_port_split_list) != 2:
13
+ return uri
14
+ user__pass_split_list = user_pass__ip_port_split_list[0].split(':')
15
+ if len(user__pass_split_list) != 2:
16
+ return uri
17
+ user = user__pass_split_list[0]
18
+ pwd = user__pass_split_list[1]
19
+ pwd_enc = cls.enc_pwd(pwd)
20
+ return f'{protocol_split_list[0]}://{user}:{pwd_enc}@{user_pass__ip_port_split_list[1]}'
21
+
22
+ @staticmethod
23
+ def enc_pwd(pwd: str, plain_len=3):
24
+ pwd_enc = pwd
25
+ if len(pwd_enc) > plain_len:
26
+ pwd_enc = f'{pwd_enc[:plain_len]}{"*" * (len(pwd_enc) - plain_len)}'
27
+ return pwd_enc
28
+
29
+
30
+ class StrHelper:
31
+ def __init__(self, strx: str):
32
+ self.strx = strx
33
+
34
+ def judge_contains_str_list(self, str_list: list, ignore_case=True):
35
+ for str1 in str_list:
36
+ if str1 in self.strx:
37
+ return True
38
+ if ignore_case:
39
+ if str1.lower() in self.strx.lower():
40
+ return True
41
+ return False
42
+
43
+
44
+ if __name__ == '__main__':
45
+ str1 = "amqp://admin:abc234@108.55.33.99:5672/"
46
+ str2 = "redis://:myRedisPass1234@127.0.0.1:6379/0"
47
+ print(PwdEnc.enc_broker_uri(str1))
48
+ print(PwdEnc.enc_broker_uri(str2))
49
+ print(PwdEnc.enc_pwd('465460dsdsd'))
50
+
51
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: funboost
3
- Version: 44.4
3
+ Version: 44.6
4
4
  Summary: pip install funboost,python全功能分布式函数调度框架,。支持python所有类型的并发模式和一切知名消息队列中间件,支持如 celery dramatiq等框架整体作为funboost中间件,python函数加速器,框架包罗万象,用户能想到的控制功能全都有。一统编程思维,兼容50% python业务场景,适用范围广。只需要一行代码即可分布式执行python一切函数,99%用过funboost的pythoner 感受是 简易 方便 强劲 强大,相见恨晚
5
5
  Home-page: https://github.com/ydf0509/funboost
6
6
  Author: bfzs
@@ -1,9 +1,9 @@
1
- funboost/__init__.py,sha256=5ElyfATJ1YHMtE87AY-GMr6NHoojJSfe01SuYgSNu3g,3834
1
+ funboost/__init__.py,sha256=irC9sEAeKqf2qdJ549XxuVgaeIBcnbJy4biujms--aE,3957
2
2
  funboost/__init__old.py,sha256=07A1MLsxLtuRQQOIfDyphddOwNBrGe34enoHWAnjV14,20379
3
3
  funboost/__main__.py,sha256=-6Nogi666Y0LN8fVm3JmHGTOk8xEGWvotW_GDbSaZME,1065
4
- funboost/constant.py,sha256=Yxt3WJt9D8ybcrgiojOy0qjnq5mffwTnTJplerGL0Oo,7188
4
+ funboost/constant.py,sha256=-QFaxH3tX9AlK9Fmq2hNjxuBWXpmnpCpuZayj7c-xW8,7768
5
5
  funboost/funboost_config_deafult.py,sha256=K-kCFGEjD107wHWFspNrIWsPNSVteP2Xww1yRbXd-Wk,6651
6
- funboost/set_frame_config.py,sha256=fnc9yIWTxVnqFrUQrXTGPWBzHgPNebsf-xnzYpktY9U,14339
6
+ funboost/set_frame_config.py,sha256=ueaAjIOSGXrOj-Wyz5rov2tQFnkQHBePJrJ8k0tO3jM,14344
7
7
  funboost/assist/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  funboost/assist/celery_helper.py,sha256=EOxsl-y65JPwHrmL0LTGAj1nKLbS0qyRbuXcJ0xo9wc,5721
9
9
  funboost/assist/dramatiq_helper.py,sha256=9mUyfBMAJXzwvB8LwOmapn3rY30a6UXt3tNOfL6OXoM,2106
@@ -33,10 +33,11 @@ funboost/concurrent_pool/backup/async_pool_executor0223.py,sha256=RVUZiylUvpTm6U
33
33
  funboost/concurrent_pool/backup/async_pool_executor_back.py,sha256=KL6zEQaa1KkZOlAO85mCC1gwLm-YC5Ghn21IUom0UKM,9598
34
34
  funboost/concurrent_pool/backup/async_pool_executor_janus.py,sha256=OHMWJ9l3EYTpPpcrPrGGKd4K0tmQ2PN8HiX0Dta0EOo,5728
35
35
  funboost/consumers/__init__.py,sha256=ZXY_6Kut1VYNQiF5aWEgIWobsW1ht9YUP0TdRZRWFqI,126
36
- funboost/consumers/base_consumer.py,sha256=lKJQwQJfonZDrV8zcglGOHEBjcACdMnq8kQhIMxY2lw,76558
36
+ funboost/consumers/base_consumer.py,sha256=YCydqshbuoi46TRSoHdMtgE_ZYBVs9keb7h5ZoNG18w,76800
37
37
  funboost/consumers/celery_consumer.py,sha256=9gtz7nlZkmv3ErmaseT0_Q__ltSPx-fOcwi-TMPoaLA,9220
38
38
  funboost/consumers/confirm_mixin.py,sha256=eY6fNwx51Hn4bQSYRjyTRwOqfCGsikVnd2Ga_Ep31N4,6062
39
39
  funboost/consumers/dramatiq_consumer.py,sha256=ozmeAfeF0U-YNYHK4suQB0N264h5AZdfMH0O45Mh-8A,2229
40
+ funboost/consumers/empty_consumer.py,sha256=pU5py60l-JDQFTJlaMpfuFyzRGqDUnOrpKhG9gOg39A,759
40
41
  funboost/consumers/http_consumer.py,sha256=2MVqEzHW9qIKWvgIQS7VncGfvpmWhQ3BWWjfyHWC-as,2179
41
42
  funboost/consumers/http_consumer000.py,sha256=PiiSLSQB-hHgS1vAn8DoHD2siC3zO6_kKjVW0g6AFIc,4379
42
43
  funboost/consumers/httpsqs_consumer.py,sha256=kaqOcrKMLrSR27XqeiheRDmpF1KDVDghgbHcefTjqt8,1171
@@ -59,13 +60,14 @@ funboost/consumers/rabbitmq_pika_consumer.py,sha256=51IkRUSR0v2v7BUlA8oInx81VGeO
59
60
  funboost/consumers/rabbitmq_pika_consumerv0.py,sha256=rIQToBTBqGdjnzMhg0vyZMY87NtK_Uw8ggiTu39JQ_w,4777
60
61
  funboost/consumers/rabbitmq_rabbitpy_consumer.py,sha256=xxINY037pmgF3_lJA-zhf9qUIUx6DdqC7tsUOQL3dL4,1330
61
62
  funboost/consumers/redis_brpoplpush_consumer.py,sha256=HqjgjjEibq7D-5XFpJtyaPvtfXD5zbq9cjSHx4aM1gU,2952
62
- funboost/consumers/redis_consumer.py,sha256=63QbUfEftr29XNG7989UgLWM9Adn01A5gPiBMMGQc0w,2559
63
- funboost/consumers/redis_consumer_ack_able.py,sha256=e83pwbxYKdXfD-suUh_5uTQwomBB2-FU0xo_iRvLKFo,7221
63
+ funboost/consumers/redis_consumer.py,sha256=z4opk78FHIes8LJVnDlQtmEQjuJEZo-g3NFN04lBStE,2668
64
+ funboost/consumers/redis_consumer_ack_able.py,sha256=7zP9BQNfONLBbYJFjgNtIPVqbHwklAdcPUIA8Y7M8go,7411
65
+ funboost/consumers/redis_consumer_ack_using_timeout.py,sha256=PMSafTcj5cKrVZ10IkrjU3zIdmHevcuVRT4WxslrLSw,4204
64
66
  funboost/consumers/redis_consumer_priority.py,sha256=C-ftnlGPPoB7YV3GvwLu9POVGDn_GKlBqO6NlsZ-hdY,5566
65
- funboost/consumers/redis_consumer_simple.py,sha256=0iGaZpTOwbmbz3PkpUjy-PmsN1PmAFweA-LACv1TyZU,806
67
+ funboost/consumers/redis_consumer_simple.py,sha256=3YrmxSRh8dpece_JR3Lwx8zsn-GBSP1S92lhUIQ3FoU,804
66
68
  funboost/consumers/redis_filter.py,sha256=rKNFz8mxVo4n4o8v3MP4UqdPAtoK7msQ-1xRgzFfts0,7290
67
69
  funboost/consumers/redis_pubsub_consumer.py,sha256=8V8EqobKpEXzpsQx_H3A-JBKLsWOsE0n16g62tUMMYY,1122
68
- funboost/consumers/redis_stream_consumer.py,sha256=xRfrtpCHxBpPHSto1mu3URN7IivX3klFgQM8IxC5tqs,6396
70
+ funboost/consumers/redis_stream_consumer.py,sha256=LVQa19MDfSlC8SYSYFPwJnJi62UIzfPHAbBVysLmNw8,6538
69
71
  funboost/consumers/rocketmq_consumer.py,sha256=23KLRz8iO9e_x7asrceRJYhwJFMruUgmKw7m3pHVkw0,1692
70
72
  funboost/consumers/rq_consumer.py,sha256=JX84k6Jiv4pBiQMmnhdJ7s7Qz4ub5TWS4T7qTF-WdlM,876
71
73
  funboost/consumers/sqlachemy_consumer.py,sha256=PawUaNV7EZWBQVWXkGaXy1Z16hUgxU4BLDeUFR83ewM,1300
@@ -74,7 +76,7 @@ funboost/consumers/txt_file_consumer.py,sha256=Uelk6q8hYPudofJXMTaCmg_td7z7HAcZG
74
76
  funboost/consumers/udp_consumer.py,sha256=l1ll7RL87KK-L1F_DLZccO2ghxFsZtbWUJVXAOCQUx8,1633
75
77
  funboost/consumers/zeromq_consumer.py,sha256=2ZAdo01k7EVZN38Eb9CWCd2hepqLM9YHE1qVBxnCPok,4346
76
78
  funboost/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
- funboost/contrib/api_publish_msg.py,sha256=8khUiOjbiaTuNlOU4_FMBYYNLkwHssPw-vnlE0iixVk,2480
79
+ funboost/contrib/api_publish_msg.py,sha256=6U7K1rW3vACf8PvxraHqcDh8JQqcDBf5njEWo1P_xg0,2648
78
80
  funboost/contrib/django_db_deco.py,sha256=RJaRUYdVqS10gWqM4Ncs0Lngox52SUaqIIn5GK5a8Uo,865
79
81
  funboost/contrib/queue2queue.py,sha256=4-28ULM7PTbmbOw8DG9rjlMUQCDkJNcUqkmdHAkGg2c,4898
80
82
  funboost/contrib/redis_consume_latest_msg_broker.py,sha256=ESortBZ2qu_4PBCa3e3FeL2k_PClZNb74_v55HV-BOg,1902
@@ -86,8 +88,9 @@ funboost/core/current_task.py,sha256=rAIQVLqYqtlHVRkjl17yki-mqvuMb640ssGmto4RSdA
86
88
  funboost/core/exceptions.py,sha256=pLF7BkRJAfDiWp2_xGZqencmwdPiSQI1NENbImExknY,1311
87
89
  funboost/core/fabric_deploy_helper.py,sha256=foieeqlNySuU9axJzNF6TavPjIUSYBx9UO3syVKUiyY,9999
88
90
  funboost/core/funboost_config_getter.py,sha256=TDccp5pQamkoJXkwyPwGsQGDJY8ej8ZT8L8RESSAD2w,382
91
+ funboost/core/funboost_current_task_context_thread.py,sha256=RRhqmRl943jBccgTrsfra4lS20X0zB2TtLAUaZn_A18,441
89
92
  funboost/core/funboost_time.py,sha256=IbB4dFCpg3oGUe90ssAJ_x0eDPtAVfvsUr4esdoKaOk,1777
90
- funboost/core/func_params_model.py,sha256=UWpPujyCj5xwsu6kqjSneDmekNTWkqt0AoLlEDl2RmA,19173
93
+ funboost/core/func_params_model.py,sha256=Lr15r6KOxQJNEszV5GS3ASUmRm2JJaHC_fcDQbNB_w0,19501
91
94
  funboost/core/function_result_status_config.py,sha256=PyjqAQOiwsLt28sRtH-eYRjiI3edPFO4Nde0ILFRReE,1764
92
95
  funboost/core/function_result_status_saver.py,sha256=UdokGSwU630t70AZnT9Ecj7GpYXORBDivlc9kadoI2E,9172
93
96
  funboost/core/helper_funs.py,sha256=1MZjedV6TGdaAjmj9q-ykgoTI_BtG9ZQm58PLOMVdDM,2362
@@ -102,9 +105,9 @@ funboost/core/cli/discovery_boosters.py,sha256=mbEyv0bUIGcmgkfXLI_Q1IK1QvVwKyro8
102
105
  funboost/core/cli/funboost_cli_user_templ.py,sha256=XUpKLxRKtYfebPUM8wii64kB0HW8L7j9LnRpT0xCfQI,2243
103
106
  funboost/core/cli/funboost_fire.py,sha256=OT0SNi9Zb0Tom2E0cWuArQs0obUowAA_rpCF7GdaKPs,5065
104
107
  funboost/factories/__init__.py,sha256=s7kKKjR1HU5eMjPD6r5b-SXTVMo1zBp2JjOAtkyt5Yo,178
105
- funboost/factories/broker_kind__publsiher_consumer_type_map.py,sha256=2fWuNVDOYbs8CCrQnQtWIc3wwQ5a9AOFEd7-cufj3I8,9630
106
- funboost/factories/consumer_factory.py,sha256=rPceMsUr2mrcFXL-_3kQGknNiADjfgTh9wXG1qd8yAw,1041
107
- funboost/factories/publisher_factotry.py,sha256=JOvECeovdDRXWvh_dqnNoXX-A3M9vUjVRMCpaCl_R_Q,2040
108
+ funboost/factories/broker_kind__publsiher_consumer_type_map.py,sha256=fra2cuBiFLtEaPKnkPTaC7YAoHahOfZ6HNvhUwt71Mc,9988
109
+ funboost/factories/consumer_factory.py,sha256=EaAw3OZJkGepkQxKkDvMshHjIVOQva_N6nUEhLO4JwU,1500
110
+ funboost/factories/publisher_factotry.py,sha256=4651sxnbIAi6sFEUQdlUuv8UkbMQIE_Pbzm-1DimAs8,2535
108
111
  funboost/function_result_web/app.py,sha256=WFAsAoPqCVeTxKS31UvkAhuRqUurg-j8D3c9RtHZEyY,5059
109
112
  funboost/function_result_web/functions.py,sha256=qIyzwxj6GgxsCuXdEBKcFkpBEGwDbLI8hGlm6xddJOc,7514
110
113
  funboost/function_result_web/__pycache__/app.cpython-37.pyc,sha256=p-jwU7xf31KOJhmhNXqj6J79PTxjMbiTU16gAotpSEw,4045
@@ -128,6 +131,7 @@ funboost/publishers/celery_publisher.py,sha256=uc9N1uLW74skUCw8dsnvxORM2O3cy4SiI
128
131
  funboost/publishers/celery_publisher000.py,sha256=2XLOyU2__vlIUTi5L15uf0BJqAIjxbc3kCLIRDSOY9w,3966
129
132
  funboost/publishers/confluent_kafka_publisher.py,sha256=B4rF6gljixOMyN6L2eL1gzqTv97uoy7TTzgKUhHljEQ,4749
130
133
  funboost/publishers/dramatiq_publisher.py,sha256=IH9F-Ps1r94WDu2a7cZbJqWlBgblDbEcpjGj2rl-9WE,1413
134
+ funboost/publishers/empty_publisher.py,sha256=Com5m-mkjXpcWxKZZneymhLNaRJNaGAtvwjhwHmECgg,870
131
135
  funboost/publishers/http_publisher.py,sha256=pS3z_AVqH6h4PAgqB7usihvzLJP5ZzfPKQRMQfHrJHQ,753
132
136
  funboost/publishers/httpsqs_publisher.py,sha256=PS6h8-mn3wYFfMOsPt4tal8p0yZgYgrYYO9ZnIl9CwU,2737
133
137
  funboost/publishers/huey_publisher.py,sha256=9HBrsqTO61iPB1nI5fYOQNPuOaX4I4Wmb1BRNODAE_0,1118
@@ -170,12 +174,13 @@ funboost/utils/__init__.py,sha256=rAyXE7lgCo_3VdMvGrIJiqsTHv2nZPTJDTj1f6s_KgE,58
170
174
  funboost/utils/apscheduler_monkey.py,sha256=CcUISbqX6nMWSxr_QjZ26IvvhUk_ojYZWRaKenpsKfE,3124
171
175
  funboost/utils/block_exit.py,sha256=BnfxNYo3lnmhk686RAEoc4u3D4RU_iEMMMgu5L8gIuI,96
172
176
  funboost/utils/bulk_operation.py,sha256=B4FBxlz5f4oqlKDWqer7axn4gnDSfsYoMW2zSUCnGcQ,10101
177
+ funboost/utils/class_utils.py,sha256=EZ98CzeoaN2H8iOABTOPefMVfdrii9XDwATqZ0_CkUQ,1153
173
178
  funboost/utils/ctrl_c_end.py,sha256=FgT9An-qsUA5gW-V-UKWqOh5shC7C_uvTFn0fS7i8GI,439
174
179
  funboost/utils/custom_pysnooper.py,sha256=7yXLKEMY_JjPRRt0Y0N-wV2CFhILlYNh40Y6uRBUaj8,5923
175
- funboost/utils/decorators.py,sha256=MaoftkcBXLqRNX8KPik7K2jK5p6Brx2QfPitNaJQCm0,26541
180
+ funboost/utils/decorators.py,sha256=lyi9TCBg__7xkoV17AZhRItTn95vU2XMtOxfXJVV5B4,26601
176
181
  funboost/utils/develop_log.py,sha256=Wsx0ongGjTit5xqgk1BztYlVEkC6d0-Y7GENXLedVqY,271
177
182
  funboost/utils/expire_lock.py,sha256=AOkd1KlvZeIwQaz8ZoKxLpGxWgqQ4mfNHcFphh04o8Q,4732
178
- funboost/utils/json_helper.py,sha256=HDdtLyZBGpWbUm7vmTypKXd8K-Hb-9BaxpdmRlKMYUI,1849
183
+ funboost/utils/json_helper.py,sha256=GvPVJJ2f6MvOmABP2t006yBxXQIFJSJAeshiNoJ9Vsk,2259
179
184
  funboost/utils/mongo_util.py,sha256=g2AdsanKm2v9X-OaTCS6hx_0JvRw5WukXIttN3TD9sI,3069
180
185
  funboost/utils/monkey_color_log.py,sha256=QChhQMTB6phZ2eBaPq-9tFZF1n7pWeJgmJPIB_ugkvs,7367
181
186
  funboost/utils/monkey_patches.py,sha256=vGmtPuTwNLbS8T3gpufSC_cD8_Vnp85roZrCpJZUSE4,2890
@@ -186,7 +191,8 @@ funboost/utils/redis_manager.py,sha256=iG3e9k3oedtKcGwDnjKA0hUFsk_MSlvVM2C3m3K97
186
191
  funboost/utils/redis_manager_old.py,sha256=c3RBXN6dM3kjVBqkCdotpZuYmFs4d9emfp5iJgC61Us,5516
187
192
  funboost/utils/resource_monitoring.py,sha256=EWq7hqQLM2hYpbkv4sVw9YcpHLxfg8arcGz-QXw9lf0,5710
188
193
  funboost/utils/restart_python.py,sha256=bFbV0_24ajL8hBwVRLxWe9v9kTwiX1fGLhXRroNnmgQ,1418
189
- funboost/utils/simple_data_class.py,sha256=CPiiywEAUSK4eKIxGlzOua1ZSkO_sVsMt157i8MwWO0,1543
194
+ funboost/utils/simple_data_class.py,sha256=AVaMOyM2o7fszFoG6U8qGly7fIUZt10o5x5mIFYzI9k,2277
195
+ funboost/utils/str_utils.py,sha256=Mxi8BW3-QTBozxioTKpmEh00hOibT-_5dctMjz4miUs,1608
190
196
  funboost/utils/time_util.py,sha256=smWhB0fdxgazBYI-t2E61mcIlBk78GcVnl2M8Ko8jVQ,5533
191
197
  funboost/utils/un_strict_json_dumps.py,sha256=uh2mXNRCq5dJcqMhb9CkfvehfEGYZAgI6RY1oLcYX_M,408
192
198
  funboost/utils/dependency_packages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -265,9 +271,9 @@ funboost/utils/pysnooper_ydf/utils.py,sha256=evSmGi_Oul7vSP47AJ0DLjFwoCYCfunJZ1m
265
271
  funboost/utils/pysnooper_ydf/variables.py,sha256=QejRDESBA06KG9OH4sBT4J1M55eaU29EIHg8K_igaXo,3693
266
272
  funboost/utils/times/__init__.py,sha256=Y4bQD3SIA_E7W2YvHq2Qdi0dGM4H2DxyFNdDOuFOq1w,2417
267
273
  funboost/utils/times/version.py,sha256=11XfnZVVzOgIhXXdeN_mYfdXThfrsbQHpA0wCjz-hpg,17
268
- funboost-44.4.dist-info/LICENSE,sha256=9EPP2ktG_lAPB8PjmWV-c9BiaJHc_FP6pPLcUrUwx0E,11562
269
- funboost-44.4.dist-info/METADATA,sha256=YDADellqruEZqdFJLMy2TQMJLXQ-MO_LfjbtGBONgf0,31692
270
- funboost-44.4.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
271
- funboost-44.4.dist-info/entry_points.txt,sha256=BQMqRALuw-QT9x2d7puWaUHriXfy3wIzvfzF61AnSSI,97
272
- funboost-44.4.dist-info/top_level.txt,sha256=K8WuKnS6MRcEWxP1NvbmCeujJq6TEfbsB150YROlRw0,9
273
- funboost-44.4.dist-info/RECORD,,
274
+ funboost-44.6.dist-info/LICENSE,sha256=9EPP2ktG_lAPB8PjmWV-c9BiaJHc_FP6pPLcUrUwx0E,11562
275
+ funboost-44.6.dist-info/METADATA,sha256=v5NmHcGZoe1bkKbdpCujOZ6asg_fdLxAi-hG9k1VRLg,31692
276
+ funboost-44.6.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
277
+ funboost-44.6.dist-info/entry_points.txt,sha256=BQMqRALuw-QT9x2d7puWaUHriXfy3wIzvfzF61AnSSI,97
278
+ funboost-44.6.dist-info/top_level.txt,sha256=K8WuKnS6MRcEWxP1NvbmCeujJq6TEfbsB150YROlRw0,9
279
+ funboost-44.6.dist-info/RECORD,,