funboost 48.7__py3-none-any.whl → 48.9__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 +1 -1
- funboost/__main__.py +2 -0
- funboost/concurrent_pool/custom_threadpool_executor.py +1 -1
- funboost/constant.py +17 -2
- funboost/consumers/base_consumer.py +42 -28
- funboost/consumers/rabbitmq_amqpstorm_consumer.py +6 -1
- funboost/core/active_cousumer_info_getter.py +50 -10
- funboost/core/booster.py +2 -1
- funboost/core/cli/funboost_fire.py +10 -0
- funboost/core/current_task.py +17 -0
- funboost/core/func_params_model.py +21 -17
- funboost/core/loggers.py +1 -0
- funboost/core/msg_result_getter.py +1 -0
- funboost/funboost_config_deafult.py +1 -1
- funboost/function_result_web/__pycache__/app.cpython-37.pyc +0 -0
- funboost/function_result_web/__pycache__/app.cpython-39.pyc +0 -0
- funboost/function_result_web/__pycache__/functions.cpython-37.pyc +0 -0
- funboost/function_result_web/__pycache__/functions.cpython-39.pyc +0 -0
- funboost/function_result_web/app.py +42 -2
- funboost/function_result_web/app_debug_start.py +6 -0
- funboost/function_result_web/functions.py +66 -3
- funboost/function_result_web/static/js/form-memory.js +92 -0
- funboost/function_result_web/static/js_cdn/chart.js +20 -0
- funboost/function_result_web/static/js_cdn/tabulator-tables@5.5.0/dist/js/tabulator.min.js +1 -1
- funboost/function_result_web/templates/about.html +0 -9
- funboost/function_result_web/templates/conusme_speed.html +2 -2
- funboost/function_result_web/templates/fun_result_table.html +1 -1
- funboost/function_result_web/templates/index.html +64 -9
- funboost/function_result_web/templates/queue_op.html +419 -28
- funboost/function_result_web/templates/rpc_call.html +312 -0
- funboost/function_result_web/templates/running_consumer_by_ip.html +2 -2
- funboost/function_result_web/templates/running_consumer_by_queue_name.html +2 -2
- funboost/publishers/rabbitmq_amqpstorm_publisher.py +1 -1
- funboost/utils/ctrl_c_end.py +19 -1
- funboost/utils/dependency_packages_in_pythonpath/aioredis/readme.md +6 -0
- funboost/utils/dependency_packages_in_pythonpath/readme.md +6 -0
- {funboost-48.7.dist-info → funboost-48.9.dist-info}/METADATA +173 -81
- {funboost-48.7.dist-info → funboost-48.9.dist-info}/RECORD +42 -39
- {funboost-48.7.dist-info → funboost-48.9.dist-info}/WHEEL +1 -1
- funboost/function_result_web/templates/index_/321/204/342/225/225/320/235/321/205/320/237/320/277/321/206/320/232/320/250/321/205/320/237/320/260.html +0 -153
- {funboost-48.7.dist-info → funboost-48.9.dist-info}/LICENSE +0 -0
- {funboost-48.7.dist-info → funboost-48.9.dist-info}/entry_points.txt +0 -0
- {funboost-48.7.dist-info → funboost-48.9.dist-info}/top_level.txt +0 -0
funboost/__init__.py
CHANGED
funboost/__main__.py
CHANGED
|
@@ -18,6 +18,7 @@ def _check_pass_params():
|
|
|
18
18
|
|
|
19
19
|
def main():
|
|
20
20
|
_check_pass_params()
|
|
21
|
+
|
|
21
22
|
|
|
22
23
|
fire.Fire(BoosterFire, )
|
|
23
24
|
|
|
@@ -31,4 +32,5 @@ python -m funboost --project_root_path=/codes/funboost --booster_dirs_str=tes
|
|
|
31
32
|
python -m funboost --project_root_path=/codes/funboost --booster_dirs_str=test_frame/test_funboost_cli/test_find_boosters --max_depth=2 push test_find_queue1 --x=1 --y=2
|
|
32
33
|
|
|
33
34
|
|
|
35
|
+
python -m funboost --project_root_path=/codes/funboost start_web
|
|
34
36
|
'''
|
|
@@ -98,7 +98,7 @@ class ThreadPoolExecutorShrinkAble(Executor, FunboostFileLoggerMixin, LoggerLeve
|
|
|
98
98
|
# MIN_WORKERS = 5 # 最小值可以设置为0,代表线程池无论多久没有任务最少要保持多少个线程待命。
|
|
99
99
|
# KEEP_ALIVE_TIME = 60 # 这个参数表名,当前线程从queue.get(block=True, timeout=KEEP_ALIVE_TIME)多久没任务,就线程结束。
|
|
100
100
|
|
|
101
|
-
MIN_WORKERS =
|
|
101
|
+
MIN_WORKERS = 1
|
|
102
102
|
KEEP_ALIVE_TIME = 60
|
|
103
103
|
|
|
104
104
|
def __init__(self, max_workers: int = None, thread_name_prefix='',work_queue_maxsize=10):
|
funboost/constant.py
CHANGED
|
@@ -108,8 +108,23 @@ class ConstStrForClassMethod:
|
|
|
108
108
|
OBJ_INIT_PARAMS = 'obj_init_params'
|
|
109
109
|
CLS_MODULE = 'cls_module'
|
|
110
110
|
CLS_FILE = 'cls_file'
|
|
111
|
-
|
|
112
111
|
class RedisKeys:
|
|
113
112
|
REDIS_KEY_PAUSE_FLAG = 'funboost_pause_flag'
|
|
114
113
|
REDIS_KEY_STOP_FLAG = 'funboost_stop_flag'
|
|
115
|
-
QUEUE__MSG_COUNT_MAP = 'funboost_queue__msg_count_map'
|
|
114
|
+
QUEUE__MSG_COUNT_MAP = 'funboost_queue__msg_count_map'
|
|
115
|
+
FUNBOOST_QUEUE__CONSUMER_PARAMS= 'funboost_queue__consumer_parmas'
|
|
116
|
+
FUNBOOST_QUEUE__RUN_COUNT_MAP = 'funboost_queue__run_count_map'
|
|
117
|
+
FUNBOOST_QUEUE__RUN_FAIL_COUNT_MAP = 'funboost_queue__run_fail_count_map'
|
|
118
|
+
FUNBOOST_ALL_QUEUE_NAMES = 'funboost_all_queue_names'
|
|
119
|
+
FUNBOOST_ALL_IPS = 'funboost_all_ips'
|
|
120
|
+
|
|
121
|
+
FUNBOOST_HEARTBEAT_QUEUE__DICT_PREFIX = 'funboost_hearbeat_queue__dict:'
|
|
122
|
+
FUNBOOST_HEARTBEAT_SERVER__DICT_PREFIX = 'funboost_hearbeat_server__dict:'
|
|
123
|
+
|
|
124
|
+
@staticmethod
|
|
125
|
+
def gen_funboost_hearbeat_queue__dict_key_by_queue_name(queue_name):
|
|
126
|
+
return f'{RedisKeys.FUNBOOST_HEARTBEAT_QUEUE__DICT_PREFIX}{queue_name}'
|
|
127
|
+
|
|
128
|
+
@staticmethod
|
|
129
|
+
def gen_funboost_hearbeat_server__dict_key_by_ip(ip):
|
|
130
|
+
return f'{RedisKeys.FUNBOOST_HEARTBEAT_SERVER__DICT_PREFIX}{ip}'
|
|
@@ -165,6 +165,7 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
|
|
|
165
165
|
self._redis_filter = filter_class(self._redis_filter_key_name, consumer_params.task_filtering_expire_seconds)
|
|
166
166
|
|
|
167
167
|
self._lock_for_count_execute_task_times_every_unit_time = Lock()
|
|
168
|
+
self._async_lock_for_count_execute_task_times_every_unit_time = asyncio.Lock()
|
|
168
169
|
# self._unit_time_for_count = 10 # 每隔多少秒计数,显示单位时间内执行多少次,暂时固定为10秒。
|
|
169
170
|
# self._execute_task_times_every_unit_time = 0 # 每单位时间执行了多少次任务。
|
|
170
171
|
# self._execute_task_times_every_unit_time_fail =0 # 每单位时间执行了多少次任务失败。
|
|
@@ -193,7 +194,7 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
|
|
|
193
194
|
self.consumer_params.broker_exclusive_config = broker_exclusive_config_merge
|
|
194
195
|
|
|
195
196
|
self._stop_flag = None
|
|
196
|
-
self._pause_flag =
|
|
197
|
+
self._pause_flag = threading.Event() # 暂停消费标志,从reids读取
|
|
197
198
|
self._last_show_pause_log_time = 0
|
|
198
199
|
# self._redis_key_stop_flag = f'funboost_stop_flag'
|
|
199
200
|
# self._redis_key_pause_flag = RedisKeys.REDIS_KEY_PAUSE_FLAG
|
|
@@ -242,12 +243,27 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
|
|
|
242
243
|
# print(self.publisher_params)
|
|
243
244
|
if is_main_process:
|
|
244
245
|
self.logger.info(f'{self.queue_name} consumer 的消费者配置:\n {self.consumer_params.json_str_value()}')
|
|
246
|
+
|
|
245
247
|
atexit.register(self.join_shedual_task_thread)
|
|
246
248
|
|
|
249
|
+
self._save_consumer_params()
|
|
250
|
+
|
|
247
251
|
if self.consumer_params.is_auto_start_consuming_message:
|
|
248
252
|
_ = self.publisher_of_same_queue
|
|
249
253
|
self.start_consuming_message()
|
|
250
254
|
|
|
255
|
+
def _save_consumer_params(self):
|
|
256
|
+
"""
|
|
257
|
+
保存队列的消费者参数,以便在web界面查看。
|
|
258
|
+
:return:
|
|
259
|
+
"""
|
|
260
|
+
if self.consumer_params.is_send_consumer_hearbeat_to_redis:
|
|
261
|
+
RedisMixin().redis_db_frame.sadd(RedisKeys.FUNBOOST_ALL_QUEUE_NAMES,self.queue_name)
|
|
262
|
+
RedisMixin().redis_db_frame.hmset(RedisKeys.FUNBOOST_QUEUE__CONSUMER_PARAMS,
|
|
263
|
+
{self.queue_name: self.consumer_params.json_str_value()})
|
|
264
|
+
RedisMixin().redis_db_frame.sadd(RedisKeys.FUNBOOST_ALL_IPS,nb_log_config_default.computer_ip)
|
|
265
|
+
|
|
266
|
+
|
|
251
267
|
def _build_logger(self):
|
|
252
268
|
logger_prefix = self.consumer_params.logger_prefix
|
|
253
269
|
if logger_prefix != '':
|
|
@@ -455,15 +471,7 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
|
|
|
455
471
|
return msg
|
|
456
472
|
|
|
457
473
|
def _submit_task(self, kw):
|
|
458
|
-
|
|
459
|
-
# print(self._pause_flag)
|
|
460
|
-
if self._pause_flag == 1:
|
|
461
|
-
time.sleep(5)
|
|
462
|
-
if time.time() - self._last_show_pause_log_time > 60:
|
|
463
|
-
self.logger.warning(f'已设置 {self.queue_name} 队列中的任务为暂停消费')
|
|
464
|
-
self._last_show_pause_log_time = time.time()
|
|
465
|
-
else:
|
|
466
|
-
break
|
|
474
|
+
|
|
467
475
|
kw['body'] = self.convert_msg_before_run(kw['body'])
|
|
468
476
|
self._print_message_get_from_broker(kw['body'])
|
|
469
477
|
if self._judge_is_daylight():
|
|
@@ -528,6 +536,16 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
|
|
|
528
536
|
else:
|
|
529
537
|
self._frequency_control(self.consumer_params.qps, self._msg_schedule_time_intercal)
|
|
530
538
|
|
|
539
|
+
while 1: # 这一块的代码为支持暂停消费。
|
|
540
|
+
# print(self._pause_flag)
|
|
541
|
+
if self._pause_flag.is_set():
|
|
542
|
+
if time.time() - self._last_show_pause_log_time > 60:
|
|
543
|
+
self.logger.warning(f'已设置 {self.queue_name} 队列中的任务为暂停消费')
|
|
544
|
+
self._last_show_pause_log_time = time.time()
|
|
545
|
+
time.sleep(5)
|
|
546
|
+
else:
|
|
547
|
+
break
|
|
548
|
+
|
|
531
549
|
def __delete_eta_countdown(self, msg_body: dict):
|
|
532
550
|
self.__dict_pop(msg_body.get('extra', {}), 'eta')
|
|
533
551
|
self.__dict_pop(msg_body.get('extra', {}), 'countdown')
|
|
@@ -706,7 +724,7 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
|
|
|
706
724
|
fct_context = FctContext(function_params=function_only_params,
|
|
707
725
|
full_msg=kw['body'],
|
|
708
726
|
function_result_status=function_result_status,
|
|
709
|
-
logger=self.logger, )
|
|
727
|
+
logger=self.logger, queue_name=self.queue_name,)
|
|
710
728
|
|
|
711
729
|
try:
|
|
712
730
|
function_run = self.consuming_function
|
|
@@ -714,6 +732,7 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
|
|
|
714
732
|
fct_context.asyncio_use_thread_concurrent_mode = True
|
|
715
733
|
function_run = sync_or_async_fun_deco(function_run)
|
|
716
734
|
else:
|
|
735
|
+
pass
|
|
717
736
|
fct_context.asynco_use_thread_concurrent_mode = False
|
|
718
737
|
fct.set_fct_context(fct_context)
|
|
719
738
|
function_timeout = self._get_priority_conf(kw, 'function_timeout')
|
|
@@ -836,8 +855,8 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
|
|
|
836
855
|
if (current_function_result_status.success is False and current_retry_times == max_retry_times) or current_function_result_status.success is True:
|
|
837
856
|
await simple_run_in_executor(push_result)
|
|
838
857
|
|
|
839
|
-
|
|
840
|
-
|
|
858
|
+
async with self._async_lock_for_count_execute_task_times_every_unit_time:
|
|
859
|
+
self.metric_calculation.cal(t_start_run_fun, current_function_result_status)
|
|
841
860
|
|
|
842
861
|
self.user_custom_record_process_info_func(current_function_result_status) # 两种方式都可以自定义,记录结果.建议使用文档4.21.b的方式继承来重写
|
|
843
862
|
await self.aio_user_custom_record_process_info_func(current_function_result_status)
|
|
@@ -865,7 +884,7 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
|
|
|
865
884
|
fct_context = FctContext(function_params=function_only_params,
|
|
866
885
|
full_msg=kw['body'],
|
|
867
886
|
function_result_status=function_result_status,
|
|
868
|
-
logger=self.logger,
|
|
887
|
+
logger=self.logger,queue_name=self.queue_name,)
|
|
869
888
|
fct.set_fct_context(fct_context)
|
|
870
889
|
try:
|
|
871
890
|
corotinue_obj = self.consuming_function(**self._convert_real_function_only_params_by_conusuming_function_kind(function_only_params))
|
|
@@ -1175,7 +1194,11 @@ class MetricCalculation:
|
|
|
1175
1194
|
self.consumer._distributed_consumer_statistics.active_consumer_num)
|
|
1176
1195
|
msg += f''' 预计还需要 {need_time} 时间 才能执行完成 队列 {self.consumer.queue_name} 中的 {self.msg_num_in_broker} 个剩余任务'''
|
|
1177
1196
|
self.consumer.logger.info(msg)
|
|
1178
|
-
|
|
1197
|
+
self.last_show_remaining_execution_time = time.time()
|
|
1198
|
+
if self.consumer.consumer_params.is_send_consumer_hearbeat_to_redis is True:
|
|
1199
|
+
RedisMixin().redis_db_frame.hincrby(RedisKeys.FUNBOOST_QUEUE__RUN_COUNT_MAP,self.consumer.queue_name,self.execute_task_times_every_unit_time_temp)
|
|
1200
|
+
RedisMixin().redis_db_frame.hincrby(RedisKeys.FUNBOOST_QUEUE__RUN_FAIL_COUNT_MAP,self.consumer.queue_name,self.execute_task_times_every_unit_time_temp_fail)
|
|
1201
|
+
|
|
1179
1202
|
self.current_time_for_execute_task_times_every_unit_time = time.time()
|
|
1180
1203
|
self.consuming_function_cost_time_total_every_unit_time_tmp = 0
|
|
1181
1204
|
self.execute_task_times_every_unit_time_temp = 0
|
|
@@ -1232,22 +1255,13 @@ class DistributedConsumerStatistics(RedisMixin, FunboostFileLoggerMixin):
|
|
|
1232
1255
|
self.active_consumer_num = 1
|
|
1233
1256
|
self._last_show_consumer_num_timestamp = 0
|
|
1234
1257
|
|
|
1235
|
-
self._queue__consumer_identification_map_key_name =
|
|
1236
|
-
self._server__consumer_identification_map_key_name =
|
|
1258
|
+
self._queue__consumer_identification_map_key_name = RedisKeys.gen_funboost_hearbeat_queue__dict_key_by_queue_name(self._queue_name)
|
|
1259
|
+
self._server__consumer_identification_map_key_name = RedisKeys.gen_funboost_hearbeat_server__dict_key_by_ip(nb_log_config_default.computer_ip)
|
|
1237
1260
|
|
|
1238
1261
|
def run(self):
|
|
1239
|
-
self._send_consumer_params()
|
|
1240
1262
|
self.send_heartbeat()
|
|
1241
1263
|
self._consumer.keep_circulating(self.SEND_HEARTBEAT_INTERVAL, block=False, daemon=False)(self.send_heartbeat)()
|
|
1242
1264
|
|
|
1243
|
-
def _send_consumer_params(self):
|
|
1244
|
-
"""
|
|
1245
|
-
保存队列的消费者参数,以便在web界面查看。
|
|
1246
|
-
:return:
|
|
1247
|
-
"""
|
|
1248
|
-
self.redis_db_frame.hmset('funboost_queue__consumer_parmas',{self._consumer.queue_name: self._consumer.consumer_params.json_str_value()})
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
1265
|
def _send_heartbeat_with_dict_value(self, redis_key, ):
|
|
1252
1266
|
# 发送当前消费者进程心跳的,值是字典,按一个机器或者一个队列运行了哪些进程。
|
|
1253
1267
|
|
|
@@ -1314,8 +1328,8 @@ class DistributedConsumerStatistics(RedisMixin, FunboostFileLoggerMixin):
|
|
|
1314
1328
|
|
|
1315
1329
|
pause_flag = self.redis_db_frame.hget(RedisKeys.REDIS_KEY_PAUSE_FLAG,self._consumer.queue_name)
|
|
1316
1330
|
if pause_flag is not None and int(pause_flag) == 1:
|
|
1317
|
-
self._consumer._pause_flag
|
|
1331
|
+
self._consumer._pause_flag.set()
|
|
1318
1332
|
else:
|
|
1319
|
-
self._consumer._pause_flag
|
|
1333
|
+
self._consumer._pause_flag.clear()
|
|
1320
1334
|
|
|
1321
1335
|
|
|
@@ -30,6 +30,7 @@ class RabbitmqConsumerAmqpStorm(AbstractConsumer):
|
|
|
30
30
|
rp.channel_wrapper_by_ampqstormbaic.qos(self.consumer_params.concurrent_num)
|
|
31
31
|
rp.channel_wrapper_by_ampqstormbaic.consume(callback=callback, queue=self.queue_name, no_ack=self.consumer_params.broker_exclusive_config['no_ack'],
|
|
32
32
|
)
|
|
33
|
+
self._rp=rp
|
|
33
34
|
rp.channel.start_consuming(auto_decode=True)
|
|
34
35
|
|
|
35
36
|
def _confirm_consume(self, kw):
|
|
@@ -42,5 +43,9 @@ class RabbitmqConsumerAmqpStorm(AbstractConsumer):
|
|
|
42
43
|
|
|
43
44
|
def _requeue(self, kw):
|
|
44
45
|
# amqpstorm.Message.delivery_tag
|
|
45
|
-
print(kw['amqpstorm_message'].delivery_tag)
|
|
46
|
+
# print(kw['amqpstorm_message'].delivery_tag)
|
|
46
47
|
kw['amqpstorm_message'].nack(requeue=True)
|
|
48
|
+
# kw['amqpstorm_message'].reject(requeue=True)
|
|
49
|
+
# kw['amqpstorm_message'].ack()
|
|
50
|
+
# self.publisher_of_same_queue.publish(kw['body'])
|
|
51
|
+
|
|
@@ -52,7 +52,7 @@ class ActiveCousumerProcessInfoGetter(RedisMixin, FunboostFileLoggerMixin):
|
|
|
52
52
|
"start_timestamp": 1640604084.0780013
|
|
53
53
|
}, ...............]
|
|
54
54
|
"""
|
|
55
|
-
redis_key =
|
|
55
|
+
redis_key = RedisKeys.gen_funboost_hearbeat_queue__dict_key_by_queue_name(queue_name)
|
|
56
56
|
return self._get_all_hearbeat_info_by_redis_key_name(redis_key)
|
|
57
57
|
|
|
58
58
|
def get_all_hearbeat_info_by_ip(self, ip=None) -> typing.List[typing.Dict]:
|
|
@@ -61,15 +61,38 @@ class ActiveCousumerProcessInfoGetter(RedisMixin, FunboostFileLoggerMixin):
|
|
|
61
61
|
返回结果的格式和上面的 get_all_hearbeat_dict_by_queue_name 方法相同。
|
|
62
62
|
"""
|
|
63
63
|
ip = ip or nb_log_config_default.computer_ip
|
|
64
|
-
redis_key =
|
|
64
|
+
redis_key = RedisKeys.gen_funboost_hearbeat_server__dict_key_by_ip(ip)
|
|
65
65
|
return self._get_all_hearbeat_info_by_redis_key_name(redis_key)
|
|
66
66
|
|
|
67
|
-
def _get_all_hearbeat_info_partition_by_redis_key_prefix(self, redis_key_prefix):
|
|
68
|
-
|
|
67
|
+
# def _get_all_hearbeat_info_partition_by_redis_key_prefix(self, redis_key_prefix):
|
|
68
|
+
# keys = self.redis_db_frame.scan(0, f'{redis_key_prefix}*', count=10000)[1]
|
|
69
|
+
# infos_map = {}
|
|
70
|
+
# for key in keys:
|
|
71
|
+
# infos = self.redis_db_frame.smembers(key)
|
|
72
|
+
# dict_key = key.replace(redis_key_prefix, '')
|
|
73
|
+
# infos_map[dict_key] = []
|
|
74
|
+
# for info_str in infos:
|
|
75
|
+
# info_dict = json.loads(info_str)
|
|
76
|
+
# if self.timestamp() - info_dict['hearbeat_timestamp'] < 15:
|
|
77
|
+
# infos_map[dict_key].append(info_dict)
|
|
78
|
+
# if self.timestamp() - info_dict['current_time_for_execute_task_times_every_unit_time'] > 30:
|
|
79
|
+
# info_dict['last_x_s_execute_count'] = 0
|
|
80
|
+
# info_dict['last_x_s_execute_count_fail'] = 0
|
|
81
|
+
# return infos_map
|
|
82
|
+
|
|
83
|
+
def get_all_queue_names(self):
|
|
84
|
+
return self.redis_db_frame.smembers(RedisKeys.FUNBOOST_ALL_QUEUE_NAMES)
|
|
85
|
+
|
|
86
|
+
def get_all_ips(self):
|
|
87
|
+
return self.redis_db_frame.smembers(RedisKeys.FUNBOOST_ALL_IPS)
|
|
88
|
+
|
|
89
|
+
def _get_all_hearbeat_info_partition_by_redis_keys(self, keys):
|
|
90
|
+
|
|
91
|
+
# keys = [f'{redis_key_prefix}{queue_name}' for queue_name in queue_names]
|
|
69
92
|
infos_map = {}
|
|
70
93
|
for key in keys:
|
|
71
94
|
infos = self.redis_db_frame.smembers(key)
|
|
72
|
-
dict_key = key.replace(
|
|
95
|
+
dict_key = key.replace(RedisKeys.FUNBOOST_HEARTBEAT_QUEUE__DICT_PREFIX, '').replace(RedisKeys.FUNBOOST_HEARTBEAT_SERVER__DICT_PREFIX, '')
|
|
73
96
|
infos_map[dict_key] = []
|
|
74
97
|
for info_str in infos:
|
|
75
98
|
info_dict = json.loads(info_str)
|
|
@@ -82,13 +105,15 @@ class ActiveCousumerProcessInfoGetter(RedisMixin, FunboostFileLoggerMixin):
|
|
|
82
105
|
|
|
83
106
|
def get_all_hearbeat_info_partition_by_queue_name(self) -> typing.Dict[typing.AnyStr, typing.List[typing.Dict]]:
|
|
84
107
|
"""获取所有队列对应的活跃消费者进程信息,按队列名划分,不需要传入队列名,自动扫描redis键。请不要在 funboost_config.py 的redis 指定的db中放太多其他业务的缓存键值对"""
|
|
85
|
-
|
|
108
|
+
queue_names = self.get_all_queue_names()
|
|
109
|
+
infos_map = self._get_all_hearbeat_info_partition_by_redis_keys([RedisKeys.gen_funboost_hearbeat_queue__dict_key_by_queue_name(queue_name) for queue_name in queue_names])
|
|
86
110
|
self.logger.info(f'获取所有队列对应的活跃消费者进程信息,按队列名划分,结果是 {json.dumps(infos_map, indent=4)}')
|
|
87
111
|
return infos_map
|
|
88
112
|
|
|
89
113
|
def get_all_hearbeat_info_partition_by_ip(self) -> typing.Dict[typing.AnyStr, typing.List[typing.Dict]]:
|
|
90
114
|
"""获取所有机器ip对应的活跃消费者进程信息,按机器ip划分,不需要传入机器ip,自动扫描redis键。请不要在 funboost_config.py 的redis 指定的db中放太多其他业务的缓存键值对 """
|
|
91
|
-
|
|
115
|
+
ips = self.get_all_ips()
|
|
116
|
+
infos_map = self._get_all_hearbeat_info_partition_by_redis_keys([RedisKeys.gen_funboost_hearbeat_server__dict_key_by_ip(ip) for ip in ips])
|
|
92
117
|
self.logger.info(f'获取所有机器ip对应的活跃消费者进程信息,按机器ip划分,结果是 {json.dumps(infos_map, indent=4)}')
|
|
93
118
|
return infos_map
|
|
94
119
|
|
|
@@ -104,12 +129,12 @@ class QueueConusmerParamsGetter(RedisMixin, FunboostFileLoggerMixin):
|
|
|
104
129
|
queue__pause_map = self.redis_db_frame.hgetall(RedisKeys.REDIS_KEY_PAUSE_FLAG)
|
|
105
130
|
return {k:int(v) for k,v in queue__pause_map.items()}
|
|
106
131
|
|
|
107
|
-
def get_msg_num(self):
|
|
132
|
+
def get_msg_num(self,ignore_report_ts=False):
|
|
108
133
|
queue__msg_count_info_map = self.redis_db_frame.hgetall(RedisKeys.QUEUE__MSG_COUNT_MAP)
|
|
109
134
|
queue__msg_count_dict = {}
|
|
110
135
|
for queue_name,info_json in queue__msg_count_info_map.items():
|
|
111
136
|
info_dict = json.loads(info_json)
|
|
112
|
-
if info_dict['report_ts'] > time.time() - 15 and info_dict['last_get_msg_num_ts'] > time.time() - 1200:
|
|
137
|
+
if ignore_report_ts or (info_dict['report_ts'] > time.time() - 15 and info_dict['last_get_msg_num_ts'] > time.time() - 1200):
|
|
113
138
|
queue__msg_count_dict[queue_name] = info_dict['msg_num_in_broker']
|
|
114
139
|
return queue__msg_count_dict
|
|
115
140
|
|
|
@@ -123,11 +148,22 @@ class QueueConusmerParamsGetter(RedisMixin, FunboostFileLoggerMixin):
|
|
|
123
148
|
s+=c[filed]
|
|
124
149
|
return s
|
|
125
150
|
|
|
151
|
+
def get_queues_history_run_count(self,):
|
|
152
|
+
return self.redis_db_frame.hgetall(RedisKeys.FUNBOOST_QUEUE__RUN_COUNT_MAP)
|
|
153
|
+
|
|
154
|
+
def get_queues_history_run_fail_count(self,):
|
|
155
|
+
return self.redis_db_frame.hgetall(RedisKeys.FUNBOOST_QUEUE__RUN_FAIL_COUNT_MAP)
|
|
156
|
+
|
|
126
157
|
def get_queue_params_and_active_consumers(self):
|
|
127
158
|
queue__active_consumers_map = ActiveCousumerProcessInfoGetter().get_all_hearbeat_info_partition_by_queue_name()
|
|
159
|
+
|
|
160
|
+
queue_name_list = list(queue__active_consumers_map.keys())
|
|
161
|
+
queue__history_run_count_map = self.get_queues_history_run_count()
|
|
162
|
+
queue__history_run_fail_count_map = self.get_queues_history_run_fail_count()
|
|
163
|
+
|
|
128
164
|
queue__consumer_params_map = self.get_queue_params()
|
|
129
165
|
queue__pause_map = self.get_pause_flag()
|
|
130
|
-
queue__msg_count_dict = self.get_msg_num()
|
|
166
|
+
queue__msg_count_dict = self.get_msg_num(ignore_report_ts=True)
|
|
131
167
|
queue_params_and_active_consumers = {}
|
|
132
168
|
|
|
133
169
|
for queue, consumer_params in queue__consumer_params_map.items():
|
|
@@ -148,6 +184,10 @@ class QueueConusmerParamsGetter(RedisMixin, FunboostFileLoggerMixin):
|
|
|
148
184
|
'active_consumers':active_consumers,
|
|
149
185
|
'pause_flag':queue__pause_map.get(queue,-1),
|
|
150
186
|
'msg_num_in_broker':queue__msg_count_dict.get(queue,None),
|
|
187
|
+
|
|
188
|
+
'history_run_count':queue__history_run_count_map.get(queue,None),
|
|
189
|
+
'history_run_fail_count':queue__history_run_fail_count_map.get(queue,None),
|
|
190
|
+
|
|
151
191
|
'all_consumers_last_x_s_execute_count':all_consumers_last_x_s_execute_count,
|
|
152
192
|
'all_consumers_last_x_s_execute_count_fail':all_consumers_last_x_s_execute_count_fail,
|
|
153
193
|
'all_consumers_last_x_s_avarage_function_spend_time':all_consumers_last_x_s_avarage_function_spend_time,
|
funboost/core/booster.py
CHANGED
|
@@ -100,6 +100,7 @@ class Booster:
|
|
|
100
100
|
consuming_function = args[0]
|
|
101
101
|
self.boost_params.consuming_function = consuming_function
|
|
102
102
|
self.boost_params.consuming_function_raw = consuming_function
|
|
103
|
+
self.boost_params.consuming_function_name = consuming_function.__name__
|
|
103
104
|
# print(consuming_function)
|
|
104
105
|
# print(ClsHelper.get_method_kind(consuming_function))
|
|
105
106
|
# print(inspect.getsourcelines(consuming_function))
|
|
@@ -307,7 +308,7 @@ class BoostersManager:
|
|
|
307
308
|
跨不同的项目,发布消息。例如proj1中定义有fun1消费函数,但proj2无法直接到日proj1的函数,无法直接 fun1.push 来发布消息
|
|
308
309
|
可以使用这个方法,获取一个publisher。
|
|
309
310
|
|
|
310
|
-
publisher = BoostersManager.get_cross_project_publisher(PublisherParams(queue_name='proj1_queue', broker_kind=
|
|
311
|
+
publisher = BoostersManager.get_cross_project_publisher(PublisherParams(queue_name='proj1_queue', broker_kind=publisher_params.broker_kind))
|
|
311
312
|
publisher.publish({'x': aaa})
|
|
312
313
|
"""
|
|
313
314
|
pid = os.getpid()
|
|
@@ -127,3 +127,13 @@ class BoosterFire(object):
|
|
|
127
127
|
"""
|
|
128
128
|
for queue_name in queue_names:
|
|
129
129
|
BoostersManager.get_booster(queue_name).continue_consume()
|
|
130
|
+
|
|
131
|
+
def start_funboost_web_manager(self):
|
|
132
|
+
"""
|
|
133
|
+
启动funboost web管理器;
|
|
134
|
+
例子: start_funboost_web_manager
|
|
135
|
+
"""
|
|
136
|
+
from funboost.function_result_web.app import start_funboost_web_manager
|
|
137
|
+
start_funboost_web_manager()
|
|
138
|
+
|
|
139
|
+
start_web = start_funboost_web_manager
|
funboost/core/current_task.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import abc
|
|
2
|
+
import typing
|
|
2
3
|
import contextvars
|
|
3
4
|
from dataclasses import dataclass
|
|
4
5
|
import logging
|
|
@@ -7,6 +8,8 @@ import asyncio
|
|
|
7
8
|
|
|
8
9
|
from funboost.core.function_result_status_saver import FunctionResultStatus
|
|
9
10
|
|
|
11
|
+
|
|
12
|
+
|
|
10
13
|
""" 用法例子
|
|
11
14
|
'''
|
|
12
15
|
fct = funboost_current_task()
|
|
@@ -60,7 +63,9 @@ class FctContext:
|
|
|
60
63
|
full_msg: dict
|
|
61
64
|
function_result_status: FunctionResultStatus
|
|
62
65
|
logger: logging.Logger
|
|
66
|
+
queue_name: str
|
|
63
67
|
asyncio_use_thread_concurrent_mode: bool = False
|
|
68
|
+
|
|
64
69
|
|
|
65
70
|
# class FctContext:
|
|
66
71
|
# """
|
|
@@ -107,6 +112,11 @@ class _BaseCurrentTask(metaclass=abc.ABCMeta):
|
|
|
107
112
|
@property
|
|
108
113
|
def logger(self) -> logging.Logger:
|
|
109
114
|
return self.get_fct_context().logger
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def queue_name(self) -> str:
|
|
118
|
+
return self.get_fct_context().queue_name
|
|
119
|
+
|
|
110
120
|
|
|
111
121
|
def __str__(self):
|
|
112
122
|
return f'<{self.__class__.__name__} [{self.function_result_status.get_status_dict()}]>'
|
|
@@ -184,6 +194,13 @@ class _FctProxy:
|
|
|
184
194
|
@property
|
|
185
195
|
def logger(self) -> logging.Logger:
|
|
186
196
|
return self.fct_context.logger
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def queue_name(self) -> str:
|
|
200
|
+
return self.fct_context.queue_name
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
187
204
|
|
|
188
205
|
def __str__(self):
|
|
189
206
|
return f'<{self.__class__.__name__} [{self.function_result_status.get_status_dict()}]>'
|
|
@@ -127,17 +127,18 @@ class BoosterParams(BaseJsonAbleModel):
|
|
|
127
127
|
"""
|
|
128
128
|
|
|
129
129
|
queue_name: str # 队列名字,必传项,每个函数要使用不同的队列名字.
|
|
130
|
+
broker_kind: str = BrokerEnum.SQLITE_QUEUE # 中间件选型见3.1章节 https://funboost.readthedocs.io/zh-cn/latest/articles/c3.html
|
|
130
131
|
|
|
131
132
|
"""如果设置了qps,并且cocurrent_num是默认的50,会自动开了500并发,由于是采用的智能线程池任务少时候不会真开那么多线程而且会自动缩小线程数量。具体看ThreadPoolExecutorShrinkAble的说明
|
|
132
133
|
由于有很好用的qps控制运行频率和智能扩大缩小的线程池,此框架建议不需要理会和设置并发数量只需要关心qps就行了,框架的并发是自适应并发数量,这一点很强很好用。"""
|
|
133
134
|
concurrent_mode: str = ConcurrentModeEnum.THREADING # 并发模式,支持THREADING,GEVENT,EVENTLET,ASYNC,SINGLE_THREAD并发,multi_process_consume 支持协程/线程 叠加多进程并发,性能炸裂.
|
|
134
135
|
concurrent_num: int = 50 # 并发数量,并发种类由concurrent_mode决定
|
|
135
136
|
specify_concurrent_pool: typing.Optional[FunboostBaseConcurrentPool] = None # 使用指定的线程池/携程池,可以多个消费者共使用一个线程池,节约线程.不为None时候。threads_num失效
|
|
136
|
-
specify_async_loop: asyncio.AbstractEventLoop = None # 指定的async的loop循环,设置并发模式为async才能起作用。 有些包例如aiohttp
|
|
137
|
+
specify_async_loop: typing.Optional[asyncio.AbstractEventLoop] = None # 指定的async的loop循环,设置并发模式为async才能起作用。 有些包例如aiohttp,发送请求和httpclient的实例化不能处在两个不同的loop中,可以传过来.
|
|
137
138
|
|
|
138
139
|
"""qps:
|
|
139
140
|
强悍的控制功能,指定1秒内的函数执行次数,例如可以是小数0.01代表每100秒执行一次,也可以是50代表1秒执行50次.为None则不控频。 设置qps时候,不需要指定并发数量,funboost的能够自适应智能动态调节并发池大小."""
|
|
140
|
-
qps: typing.Union[float, int] = None
|
|
141
|
+
qps: typing.Union[float, int, None] = None
|
|
141
142
|
"""is_using_distributed_frequency_control:
|
|
142
143
|
是否使用分布式空频(依赖redis统计消费者数量,然后频率平分),默认只对当前实例化的消费者空频有效。假如实例化了2个qps为10的使用同一队列名的消费者,并且都启动,则每秒运行次数会达到20。
|
|
143
144
|
如果使用分布式空频则所有消费者加起来的总运行次数是10。"""
|
|
@@ -155,7 +156,7 @@ class BoosterParams(BaseJsonAbleModel):
|
|
|
155
156
|
is_push_to_dlx_queue_when_retry_max_times: bool = False # 函数达到最大重试次数仍然没成功,是否发送到死信队列,死信队列的名字是 队列名字 + _dlx。
|
|
156
157
|
|
|
157
158
|
|
|
158
|
-
consumin_function_decorator: typing.Callable = None # 函数的装饰器。因为此框架做参数自动转指点,需要获取精准的入参名称,不支持在消费函数上叠加 @ *args **kwargs的装饰器,如果想用装饰器可以这里指定。
|
|
159
|
+
consumin_function_decorator: typing.Optional[typing.Callable] = None # 函数的装饰器。因为此框架做参数自动转指点,需要获取精准的入参名称,不支持在消费函数上叠加 @ *args **kwargs的装饰器,如果想用装饰器可以这里指定。
|
|
159
160
|
function_timeout: typing.Union[int, float,None] = None # 超时秒数,函数运行超过这个时间,则自动杀死函数。为0是不限制。 谨慎使用,非必要别去设置超时时间,设置后性能会降低(因为需要把用户函数包装到另一个线单独的程中去运行),而且突然强制超时杀死运行中函数,可能会造成死锁.(例如用户函数在获得线程锁后突然杀死函数,别的线程再也无法获得锁了)
|
|
160
161
|
|
|
161
162
|
log_level: int = logging.DEBUG # 消费者和发布者的日志级别,建议设置DEBUG级别,不然无法知道正在运行什么消息
|
|
@@ -166,7 +167,7 @@ class BoosterParams(BaseJsonAbleModel):
|
|
|
166
167
|
is_show_message_get_from_broker: bool = False # 运行时候,是否记录从消息队列获取出来的消息内容
|
|
167
168
|
is_print_detail_exception: bool = True # 消费函数出错时候,是否打印详细的报错堆栈,为False则只打印简略的报错信息不包含堆栈.
|
|
168
169
|
|
|
169
|
-
msg_expire_senconds: typing.Union[float, int] = None # 消息过期时间,可以设置消息是多久之前发布的就丢弃这条消息,不运行. 为None则永不丢弃
|
|
170
|
+
msg_expire_senconds: typing.Union[float, int,None] = None # 消息过期时间,可以设置消息是多久之前发布的就丢弃这条消息,不运行. 为None则永不丢弃
|
|
170
171
|
|
|
171
172
|
do_task_filtering: bool = False # 是否对函数入参进行过滤去重.
|
|
172
173
|
task_filtering_expire_seconds: int = 0 # 任务过滤的失效期,为0则永久性过滤任务。例如设置过滤过期时间是1800秒 , 30分钟前发布过1 + 2 的任务,现在仍然执行,如果是30分钟以内执行过这个任务,则不执行1 + 2
|
|
@@ -174,7 +175,7 @@ class BoosterParams(BaseJsonAbleModel):
|
|
|
174
175
|
function_result_status_persistance_conf: FunctionResultStatusPersistanceConfig = FunctionResultStatusPersistanceConfig(
|
|
175
176
|
is_save_result=False, is_save_status=False, expire_seconds=7 * 24 * 3600, is_use_bulk_insert=False) # 是否保存函数的入参,运行结果和运行状态到mongodb。这一步用于后续的参数追溯,任务统计和web展示,需要安装mongo。
|
|
176
177
|
|
|
177
|
-
user_custom_record_process_info_func: typing.Callable = None # 提供一个用户自定义的保存消息处理记录到某个地方例如mysql数据库的函数,函数仅仅接受一个入参,入参类型是 FunctionResultStatus,用户可以打印参数
|
|
178
|
+
user_custom_record_process_info_func: typing.Optional[typing.Callable] = None # 提供一个用户自定义的保存消息处理记录到某个地方例如mysql数据库的函数,函数仅仅接受一个入参,入参类型是 FunctionResultStatus,用户可以打印参数
|
|
178
179
|
|
|
179
180
|
is_using_rpc_mode: bool = False # 是否使用rpc模式,可以在发布端获取消费端的结果回调,但消耗一定性能,使用async_result.result时候会等待阻塞住当前线程。
|
|
180
181
|
rpc_result_expire_seconds: int = 600 # 保存rpc结果的过期时间.
|
|
@@ -190,10 +191,11 @@ class BoosterParams(BaseJsonAbleModel):
|
|
|
190
191
|
|
|
191
192
|
is_auto_start_consuming_message: bool = False # 是否在定义后就自动启动消费,无需用户手动写 .consume() 来启动消息消费。
|
|
192
193
|
|
|
193
|
-
consuming_function: typing.Callable = None # 消费函数,在@boost时候不用指定,因为装饰器知道下面的函数.
|
|
194
|
-
consuming_function_raw: typing.Callable = None
|
|
194
|
+
consuming_function: typing.Optional[typing.Callable] = None # 消费函数,在@boost时候不用指定,因为装饰器知道下面的函数.
|
|
195
|
+
consuming_function_raw: typing.Optional[typing.Callable] = None # 不需要传递,自动生成
|
|
196
|
+
consuming_function_name: str = '' # 不需要传递,自动生成
|
|
195
197
|
|
|
196
|
-
|
|
198
|
+
|
|
197
199
|
|
|
198
200
|
broker_exclusive_config: dict = {} # 加上一个不同种类中间件非通用的配置,不同中间件自身独有的配置,不是所有中间件都兼容的配置,因为框架支持30种消息队列,消息队列不仅仅是一般的先进先出queue这么简单的概念,
|
|
199
201
|
# 例如kafka支持消费者组,rabbitmq也支持各种独特概念例如各种ack机制 复杂路由机制,有的中间件原生能支持消息优先级有的中间件不支持,每一种消息队列都有独特的配置参数意义,可以通过这里传递。每种中间件能传递的键值对可以看consumer类的 BROKER_EXCLUSIVE_CONFIG_DEFAULT
|
|
@@ -221,6 +223,7 @@ class BoosterParams(BaseJsonAbleModel):
|
|
|
221
223
|
|
|
222
224
|
@root_validator(skip_on_failure=True)
|
|
223
225
|
def check_values(cls, values: dict):
|
|
226
|
+
|
|
224
227
|
|
|
225
228
|
# 如果设置了qps,并且cocurrent_num是默认的50,会自动开了500并发,由于是采用的智能线程池任务少时候不会真开那么多线程而且会自动缩小线程数量。具体看ThreadPoolExecutorShrinkAble的说明
|
|
226
229
|
# 由于有很好用的qps控制运行频率和智能扩大缩小的线程池,此框架建议不需要理会和设置并发数量只需要关心qps就行了,框架的并发是自适应并发数量,这一点很强很好用。
|
|
@@ -233,7 +236,8 @@ class BoosterParams(BaseJsonAbleModel):
|
|
|
233
236
|
|
|
234
237
|
if values['concurrent_mode'] not in ConcurrentModeEnum.__dict__.values():
|
|
235
238
|
raise ValueError('设置的并发模式不正确')
|
|
236
|
-
if values['broker_kind'] in [BrokerEnum.REDIS_ACK_ABLE, BrokerEnum.REDIS_STREAM, BrokerEnum.REDIS_PRIORITY,
|
|
239
|
+
if values['broker_kind'] in [BrokerEnum.REDIS_ACK_ABLE, BrokerEnum.REDIS_STREAM, BrokerEnum.REDIS_PRIORITY,
|
|
240
|
+
BrokerEnum.RedisBrpopLpush,BrokerEnum.REDIS,BrokerEnum.REDIS_PUBSUB]:
|
|
237
241
|
values['is_send_consumer_hearbeat_to_redis'] = True # 需要心跳进程来辅助判断消息是否属于掉线或关闭的进程,需要重回队列
|
|
238
242
|
# if not set(values.keys()).issubset(set(BoosterParams.__fields__.keys())):
|
|
239
243
|
# raise ValueError(f'{cls.__name__} 的字段包含了父类 BoosterParams 不存在的字段')
|
|
@@ -291,16 +295,16 @@ class PriorityConsumingControlConfig(BaseJsonAbleModel):
|
|
|
291
295
|
|
|
292
296
|
function_timeout: typing.Union[float, int,None] = None
|
|
293
297
|
|
|
294
|
-
max_retry_times: int = None
|
|
298
|
+
max_retry_times: typing.Union[int,None] = None
|
|
295
299
|
|
|
296
|
-
is_print_detail_exception: bool = None
|
|
300
|
+
is_print_detail_exception: typing.Union[bool,None] = None
|
|
297
301
|
|
|
298
|
-
msg_expire_senconds: int = None
|
|
302
|
+
msg_expire_senconds: typing.Union[float, int,None] = None
|
|
299
303
|
|
|
300
|
-
is_using_rpc_mode: bool = None
|
|
304
|
+
is_using_rpc_mode: typing.Union[bool,None] = None
|
|
301
305
|
|
|
302
|
-
countdown: typing.Union[float, int] = None
|
|
303
|
-
eta: typing.Union[datetime.datetime, str] = None # 时间对象, 或 %Y-%m-%d %H:%M:%S 字符串。
|
|
306
|
+
countdown: typing.Union[float, int,None] = None
|
|
307
|
+
eta: typing.Union[datetime.datetime, str,None] = None # 时间对象, 或 %Y-%m-%d %H:%M:%S 字符串。
|
|
304
308
|
misfire_grace_time: typing.Union[int, None] = None
|
|
305
309
|
|
|
306
310
|
other_extra_params: dict = None # 其他参数, 例如消息优先级 , priority_control_config=PriorityConsumingControlConfig(other_extra_params={'priroty': priorityxx}),
|
|
@@ -324,8 +328,8 @@ class PublisherParams(BaseJsonAbleModel):
|
|
|
324
328
|
logger_name: str = '' # 队列消费者发布者的日志命名空间.
|
|
325
329
|
log_filename: typing.Optional[str] = None
|
|
326
330
|
clear_queue_within_init: bool = False # with 语法发布时候,先清空消息队列
|
|
327
|
-
consuming_function: typing.Callable = None # consuming_function 作用是 inspect 模块获取函数的入参信息
|
|
328
|
-
broker_kind: str = None
|
|
331
|
+
consuming_function: typing.Optional[typing.Callable] = None # consuming_function 作用是 inspect 模块获取函数的入参信息
|
|
332
|
+
broker_kind: typing.Optional[str] = None
|
|
329
333
|
broker_exclusive_config: dict = {}
|
|
330
334
|
should_check_publish_func_params: bool = True # 消息发布时候是否校验消息发布内容,比如有的人发布消息,函数只接受a,b两个入参,他去传2个入参,或者传参不存在的参数名字, 如果消费函数你非要写*args,**kwargs,那就需要关掉发布消息时候的函数入参检查
|
|
331
335
|
publisher_override_cls: typing.Optional[typing.Type] = None
|
funboost/core/loggers.py
CHANGED
|
@@ -52,6 +52,7 @@ class AsyncResult(RedisMixin):
|
|
|
52
52
|
@property
|
|
53
53
|
def status_and_result(self):
|
|
54
54
|
if not self._has_pop:
|
|
55
|
+
# print(f'{self.task_id} 正在等待结果')
|
|
55
56
|
redis_value = self.redis_db_filter_and_rpc_result.blpop(self.task_id, self.timeout)
|
|
56
57
|
self._has_pop = True
|
|
57
58
|
if redis_value is not None:
|
|
@@ -42,7 +42,7 @@ class BrokerConnConfig(DataClassBase):
|
|
|
42
42
|
REDIS_USERNAME = ''
|
|
43
43
|
REDIS_PASSWORD = ''
|
|
44
44
|
REDIS_PORT = 6379
|
|
45
|
-
REDIS_DB = 7 # redis消息队列所在db,请不要在这个db
|
|
45
|
+
REDIS_DB = 7 # redis消息队列所在db,请不要在这个db放太多其他键值对,以及方便你自己可视化查看你的redis db,框架里面有的功能会scan扫描unacked的键名,使用单独的db。
|
|
46
46
|
REDIS_DB_FILTER_AND_RPC_RESULT = 8 # 如果函数做任务参数过滤 或者使用rpc获取结果,使用这个db,因为这个db的键值对多,和redis消息队列db分开
|
|
47
47
|
REDIS_URL = f'redis://{REDIS_USERNAME}:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB}'
|
|
48
48
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|