funboost 42.3__py3-none-any.whl → 42.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__ = "42.3"
16
+ __version__ = "42.6"
17
17
 
18
18
  from funboost.set_frame_config import show_frame_config
19
19
 
@@ -44,7 +44,7 @@ from apscheduler.executors.pool import ThreadPoolExecutor as ApschedulerThreadPo
44
44
  from funboost.funboost_config_deafult import FunboostCommonConfig
45
45
  from funboost.concurrent_pool.single_thread_executor import SoloExecutor
46
46
 
47
- from funboost.core.function_result_status_saver import ResultPersistenceHelper, FunctionResultStatus
47
+ from funboost.core.function_result_status_saver import ResultPersistenceHelper, FunctionResultStatus, RunStatus
48
48
 
49
49
  from funboost.core.helper_funs import delete_keys_and_return_new_dict, get_publish_time
50
50
 
@@ -524,10 +524,11 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
524
524
  current_retry_times = 0
525
525
  function_only_params = delete_keys_and_return_new_dict(kw['body'])
526
526
  for current_retry_times in range(max_retry_times + 1):
527
+ current_function_result_status.run_times = current_retry_times + 1
528
+ current_function_result_status.run_status = RunStatus.running
529
+ self._result_persistence_helper.save_function_result_to_mongo(current_function_result_status)
527
530
  current_function_result_status = self._run_consuming_function_with_confirm_and_retry(kw, current_retry_times=current_retry_times,
528
- function_result_status=FunctionResultStatus(
529
- self.queue_name, self.consuming_function.__name__,
530
- kw['body']))
531
+ function_result_status=current_function_result_status)
531
532
  if (current_function_result_status.success is True or current_retry_times == max_retry_times
532
533
  or current_function_result_status._has_requeue
533
534
  or current_function_result_status._has_to_dlx_queue
@@ -538,7 +539,7 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
538
539
  time.sleep(self.consumer_params.retry_interval)
539
540
  if not (current_function_result_status._has_requeue and self.BROKER_KIND in [BrokerEnum.RABBITMQ_AMQPSTORM, BrokerEnum.RABBITMQ_PIKA, BrokerEnum.RABBITMQ_RABBITPY]): # 已经nack了,不能ack,否则rabbitmq delevar tag 报错
540
541
  self._confirm_consume(kw)
541
-
542
+ current_function_result_status.run_status = RunStatus.finish
542
543
  self._result_persistence_helper.save_function_result_to_mongo(current_function_result_status)
543
544
  if self._get_priority_conf(kw, 'do_task_filtering'):
544
545
  self._redis_filter.add_a_value(function_only_params) # 函数执行成功后,添加函数的参数排序后的键值对字符串到set中。
@@ -597,7 +598,7 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
597
598
  function_only_params = delete_keys_and_return_new_dict(kw['body']) if self._do_not_delete_extra_from_msg is False else kw['body']
598
599
  task_id = kw['body']['extra']['task_id']
599
600
  t_start = time.time()
600
- function_result_status.run_times = current_retry_times + 1
601
+ # function_result_status.run_times = current_retry_times + 1
601
602
  try:
602
603
  function_run = self.consuming_function
603
604
  if self._consuming_function_is_asyncio:
@@ -679,20 +680,20 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
679
680
  current_retry_times = 0
680
681
  function_only_params = delete_keys_and_return_new_dict(kw['body'])
681
682
  for current_retry_times in range(max_retry_times + 1):
683
+ current_function_result_status.run_times = current_retry_times + 1
684
+ current_function_result_status.run_status = RunStatus.running
685
+ self._result_persistence_helper.save_function_result_to_mongo(current_function_result_status)
682
686
  current_function_result_status = await self._async_run_consuming_function_with_confirm_and_retry(kw, current_retry_times=current_retry_times,
683
- function_result_status=FunctionResultStatus(
684
- self.queue_name, self.consuming_function.__name__,
685
- kw['body'], ),
686
- )
687
+ function_result_status=current_function_result_status )
687
688
  if current_function_result_status.success is True or current_retry_times == max_retry_times or current_function_result_status._has_requeue:
688
689
  break
689
690
  else:
690
691
  if self.consumer_params.retry_interval:
691
692
  await asyncio.sleep(self.consumer_params.retry_interval)
692
693
 
693
- # self._result_persistence_helper.save_function_result_to_mongo(function_result_status)
694
694
  if not (current_function_result_status._has_requeue and self.BROKER_KIND in [BrokerEnum.RABBITMQ_AMQPSTORM, BrokerEnum.RABBITMQ_PIKA, BrokerEnum.RABBITMQ_RABBITPY]):
695
695
  await simple_run_in_executor(self._confirm_consume, kw)
696
+ current_function_result_status.run_status = RunStatus.finish
696
697
  await simple_run_in_executor(self._result_persistence_helper.save_function_result_to_mongo, current_function_result_status)
697
698
  if self._get_priority_conf(kw, 'do_task_filtering'):
698
699
  # self._redis_filter.add_a_value(function_only_params) # 函数执行成功后,添加函数的参数排序后的键值对字符串到set中。
funboost/core/booster.py CHANGED
@@ -4,7 +4,8 @@ import os
4
4
  import types
5
5
  import typing
6
6
 
7
- from funboost.core.loggers import flogger, develop_logger,logger_prompt
7
+ from funboost.utils.ctrl_c_end import ctrl_c_recv
8
+ from funboost.core.loggers import flogger, develop_logger, logger_prompt
8
9
 
9
10
  from functools import wraps
10
11
 
@@ -12,9 +13,11 @@ from funboost.core.exceptions import BoostDecoParamsIsOldVersion
12
13
  from funboost.core.func_params_model import BoosterParams, FunctionResultStatusPersistanceConfig, PriorityConsumingControlConfig
13
14
 
14
15
  from funboost.factories.consumer_factory import get_consumer
16
+
15
17
  if typing.TYPE_CHECKING:
16
18
  from funboost.core.msg_result_getter import AsyncResult
17
19
 
20
+
18
21
  class Booster:
19
22
  """
20
23
  funboost极其重视代码能在pycharm下自动补全。元编程经常造成在pycharm下代码无法自动补全提示,主要是实现代码补全难。
@@ -117,7 +120,7 @@ class Booster:
117
120
  priority_control_config: PriorityConsumingControlConfig = None) -> AsyncResult:
118
121
  """ 多进程安全的,在fork多进程(非spawn多进程)情况下,很多包跨线程/进程不能共享中间件连接,"""
119
122
  consumer = BoostersManager.get_or_create_booster_by_queue_name(self.queue_name).consumer
120
- return consumer.publisher_of_same_queue.publish(msg=msg, task_id=task_id, priority_control_config=priority_control_config)
123
+ return consumer.publisher_of_same_queue.publish(msg=msg, task_id=task_id, priority_control_config=priority_control_config)
121
124
 
122
125
  # noinspection PyMethodMayBeStatic
123
126
  def multi_process_consume(self, process_num=1):
@@ -250,3 +253,64 @@ class BoostersManager:
250
253
  flogger.info(f'创建booster {boost_params} {boost_params.consuming_function}')
251
254
  booster = Booster(boost_params)(boost_params.consuming_function)
252
255
  return booster
256
+
257
+ @classmethod
258
+ def push(cls, queue_name, *args, **kwargs):
259
+ """push发布消息到消息队列 ;
260
+ """
261
+ cls.get_or_create_booster_by_queue_name(queue_name).push(*args, **kwargs)
262
+
263
+ @classmethod
264
+ def publish(cls, queue_name, msg):
265
+ """publish发布消息到消息队列;
266
+ """
267
+ cls.get_or_create_booster_by_queue_name(queue_name).publish(msg)
268
+
269
+ @classmethod
270
+ def consume_queues(cls, *queue_names):
271
+ """
272
+ 启动多个消息队列名的消费,多个函数队列在当前同一个进程内启动消费.
273
+ 这种方式节约总的内存,但无法利用多核cpu
274
+ """
275
+ for queue_name in queue_names:
276
+ cls.get_booster(queue_name).consume()
277
+ ctrl_c_recv()
278
+
279
+ consume = consume_queues
280
+
281
+ @classmethod
282
+ def consume_all_queues(cls):
283
+ """
284
+ 启动所有消息队列名的消费,无需一个一个函数亲自 funxx.consume()来启动,多个函数队列在当前同一个进程内启动消费.
285
+ 这种方式节约总的内存,但无法利用多核cpu
286
+ """
287
+ for queue_name in cls.get_all_queues():
288
+ cls.get_booster(queue_name).consume()
289
+ ctrl_c_recv()
290
+
291
+ consume_all = consume_all_queues
292
+
293
+ @classmethod
294
+ def multi_process_consume_queues(cls, **queue_name__process_num):
295
+ """
296
+ 启动多个消息队列名的消费,传递队列名和进程数,每个队列启动n个单独的消费进程;
297
+ 这种方式总的内存使用高,但充分利用多核cpu
298
+ 例如 multi_process_consume_queues(queue1=2,queue2=3) 表示启动2个进程消费queue1,启动3个进程消费queue2
299
+ """
300
+ for queue_name, process_num in queue_name__process_num.items():
301
+ cls.get_booster(queue_name).multi_process_consume(process_num)
302
+ ctrl_c_recv()
303
+
304
+ m_consume = multi_process_consume_queues
305
+
306
+ @classmethod
307
+ def multi_process_consume_all_queues(cls, process_num=1):
308
+ """
309
+ 启动所有消息队列名的消费,无需指定队列名,每个队列启动n个单独的消费进程;
310
+ 这种方式总的内存使用高,但充分利用多核cpu
311
+ """
312
+ for queue_name in cls.get_all_queues():
313
+ cls.get_booster(queue_name).multi_process_consume(process_num)
314
+ ctrl_c_recv()
315
+
316
+ m_consume_all = multi_process_consume_all_queues
@@ -6,7 +6,10 @@ from pathlib import Path
6
6
  import importlib.util
7
7
  # import nb_log
8
8
  from funboost.core.loggers import FunboostFileLoggerMixin
9
+ from funboost.utils.decorators import flyweight
9
10
 
11
+
12
+ @flyweight
10
13
  class BoosterDiscovery(FunboostFileLoggerMixin):
11
14
  def __init__(self, project_root_path: typing.Union[PathLike, str],
12
15
  booster_dirs: typing.List[typing.Union[PathLike, str]],
@@ -23,6 +26,7 @@ class BoosterDiscovery(FunboostFileLoggerMixin):
23
26
  self.py_file_re_str = py_file_re_str
24
27
 
25
28
  self.py_files = []
29
+ self._has_discovery_import = False
26
30
 
27
31
  def get_py_files_recursively(self, current_folder_path: Path, current_depth=0, ):
28
32
  """先找到所有py文件"""
@@ -34,15 +38,20 @@ class BoosterDiscovery(FunboostFileLoggerMixin):
34
38
  elif item.suffix == '.py':
35
39
  if self.py_file_re_str:
36
40
  if re.search(self.py_file_re_str, str(item), ):
37
- self.py_files.append(item)
41
+ self.py_files.append(str(item))
38
42
  else:
39
- self.py_files.append(item)
43
+ self.py_files.append(str(item))
40
44
  self.py_files = list(set(self.py_files))
41
- for f in self.py_files:
42
- self.logger.debug(f)
43
45
 
44
46
  def auto_discovery(self, ):
45
- """把所有py文件自动执行import,主要是把 所有的@boost函数装饰器注册到 pid_queue_name__booster_map 中"""
47
+ """把所有py文件自动执行import,主要是把 所有的@boost函数装饰器注册到 pid_queue_name__booster_map 中
48
+ 这个auto_discovery方法最好放到main里面,如果要扫描自身文件夹,没写正则排除文件本身,会无限懵逼死循环导入,无无限懵逼死循环导入
49
+ """
50
+ if self._has_discovery_import is False:
51
+ self._has_discovery_import = True
52
+ else:
53
+ pass
54
+ return # 这一个判断是避免用户执行BoosterDiscovery.auto_discovery没有放到 if __name__ == '__main__'中,导致无限懵逼死循环.
46
55
  self.logger.info(self.booster__full_path_dirs)
47
56
  for dir in self.booster__full_path_dirs:
48
57
  if not Path(dir).exists():
@@ -50,6 +59,10 @@ class BoosterDiscovery(FunboostFileLoggerMixin):
50
59
 
51
60
  self.get_py_files_recursively(Path(dir))
52
61
  for file_path in self.py_files:
62
+ self.logger.debug(f'导入模块 {file_path}')
63
+ if Path(file_path) == Path(sys._getframe(1).f_code.co_filename):
64
+ self.logger.warning(f'排除导入调用auto_discovery的模块自身 {file_path}') # 否则下面的import这个文件,会造成无限懵逼死循环
65
+ continue
53
66
  spec = importlib.util.spec_from_file_location('module', file_path)
54
67
  module = importlib.util.module_from_spec(spec)
55
68
  spec.loader.exec_module(module)
@@ -30,12 +30,10 @@ from funboost.core.cli.discovery_boosters import BoosterDiscovery
30
30
  '''
31
31
  env_dict['project_root_path'] = project_root_path
32
32
 
33
- # booster_dirs 用户可以自己增加扫描的文件夹,这样可以命令行少传了 --booster_dirs_str
34
- # BoosterDiscovery 可以多吃调用
35
- BoosterDiscovery(project_root_path, booster_dirs=[], max_depth=1,py_file_re_str=None).auto_discovery()
36
-
37
-
38
33
  if __name__ == '__main__':
34
+ # booster_dirs 用户可以自己增加扫描的文件夹,这样可以命令行少传了 --booster_dirs_str
35
+ # BoosterDiscovery 可以多次调用
36
+ BoosterDiscovery(project_root_path, booster_dirs=[], max_depth=1, py_file_re_str=None).auto_discovery() # 这个最好放到main里面,如果要扫描自身文件夹,没写正则排除文件本身,会无限懵逼死循环导入
39
37
  fire.Fire(BoosterFire, )
40
38
 
41
39
  '''
@@ -49,87 +49,81 @@ class BoosterFire(object):
49
49
  清空多个queue ; 例子: clear test_cli1_queue1 test_cli1_queue2 # 清空2个消息队列消息队列
50
50
  """
51
51
 
52
- for queue_anme in queue_names:
53
- BoostersManager.get_booster(queue_anme).clear()
52
+ for queue_name in queue_names:
53
+ BoostersManager.get_booster(queue_name).clear()
54
54
  return self
55
55
 
56
- def push(self, queue_anme, *args, **kwargs):
56
+ def push(self, queue_name, *args, **kwargs):
57
57
  """push发布消息到消息队列 ;
58
58
  例子: 假设函数是 def add(x,y) 队列名是 add_queue , 发布 1 + 2求和;
59
59
  push add_queue 1 2;
60
60
  或者 push add_queue --x=1 --y=2;
61
61
  或者 push add_queue -x 1 -y 2;
62
62
  """
63
- BoostersManager.get_booster(queue_anme).push(*args, **kwargs)
63
+ BoostersManager.push(queue_name,*args, **kwargs)
64
64
  return self
65
65
 
66
66
  def __str__(self):
67
67
  # print('over') # 这行重要,否则命令行链式调用无法自动结束
68
68
  return ''
69
69
 
70
- def publish(self, queue_anme, msg):
70
+ def publish(self, queue_name, msg):
71
71
  """publish发布消息到消息队列;
72
72
  假设函数是 def add(x,y) 队列名是 add_queue , 发布 1 + 2求和;
73
73
  publish add_queue "{'x':1,'y':2}"
74
74
  """
75
75
 
76
- BoostersManager.get_booster(queue_anme).publish(msg)
76
+ BoostersManager.publish(queue_name,msg)
77
77
  return self
78
78
 
79
- def consume(self, *queue_names: str):
79
+ def consume_queues(self, *queue_names: str):
80
80
  """
81
81
  启动多个消息队列名的消费;
82
82
  例子: consume queue1 queue2
83
83
  """
84
- for queue_anme in queue_names:
85
- BoostersManager.get_booster(queue_anme).consume()
86
- ctrl_c_recv()
84
+ BoostersManager.consume_queues(*queue_names)
87
85
 
88
- def consume_all_queues(self,):
86
+ consume = consume_queues
87
+
88
+ def consume_all_queues(self, ):
89
89
  """
90
90
  启动所有消息队列名的消费,无需指定队列名;
91
91
  例子: consume_all_queues
92
92
  """
93
- for queue_anme in BoostersManager.get_all_queues():
94
- BoostersManager.get_booster(queue_anme).consume()
95
- ctrl_c_recv()
93
+ BoostersManager.consume_all_queues()
96
94
 
97
95
  consume_all = consume_all_queues
98
96
 
99
- def multi_process_consume_all_queues(self,process_num=1):
97
+ def multi_process_consume_queues(self, **queue_name__process_num):
100
98
  """
101
- 启动所有消息队列名的消费,无需指定队列名,每个队列启动n个单独的消费进程;
102
- 例子: multi_process_consume_all_queues 2
99
+ 使用多进程启动消费,每个队列开启多个单独的进程消费;
100
+ 例子: m_consume --queue1=2 --queue2=3 # queue1启动两个单独进程消费 queue2 启动3个单独进程消费
103
101
  """
104
- for queue_anme in BoostersManager.get_all_queues():
105
- BoostersManager.get_booster(queue_anme).multi_process_consume(process_num)
106
- ctrl_c_recv()
102
+ BoostersManager.multi_process_consume_queues(**queue_name__process_num)
107
103
 
108
- m_consume_all = multi_process_consume_all_queues
104
+ m_consume = multi_process_consume_queues
109
105
 
110
- def multi_process_consume(self, **queue_name__process_num):
106
+ def multi_process_consume_all_queues(self, process_num=1):
111
107
  """
112
- 使用多进程启动消费,每个队列开启多个单独的进程消费;
113
- 例子: m_consume --queue1=2 --queue2=3 # queue1启动两个单独进程消费 queue2 启动3个单独进程消费
108
+ 启动所有消息队列名的消费,无需指定队列名,每个队列启动n个单独的消费进程;
109
+ 例子: multi_process_consume_all_queues 2
114
110
  """
115
- for queue_anme, process_num in queue_name__process_num.items():
116
- BoostersManager.get_booster(queue_anme).multi_process_consume(process_num)
117
- ctrl_c_recv()
111
+ BoostersManager.multi_process_consume_all_queues(process_num)
118
112
 
119
- m_consume = multi_process_consume
113
+ m_consume_all = multi_process_consume_all_queues
120
114
 
121
115
  def pause(self, *queue_names: str):
122
116
  """
123
117
  暂停多个消息队列名的消费;
124
118
  例子: pause queue1 queue2
125
119
  """
126
- for queue_anme in queue_names:
127
- BoostersManager.get_booster(queue_anme).pause()
120
+ for queue_name in queue_names:
121
+ BoostersManager.get_booster(queue_name).pause()
128
122
 
129
123
  def continue_consume(self, *queue_names: str):
130
124
  """
131
125
  继续多个消息队列名的消费;
132
126
  例子: continue_consume queue1 queue2
133
127
  """
134
- for queue_anme in queue_names:
135
- BoostersManager.get_booster(queue_anme).continue_consume()
128
+ for queue_name in queue_names:
129
+ BoostersManager.get_booster(queue_name).continue_consume()
@@ -20,6 +20,9 @@ from funboost.utils.mongo_util import MongoMixin
20
20
  # from nb_log import LoggerMixin
21
21
  from funboost.core.loggers import FunboostFileLoggerMixin
22
22
 
23
+ class RunStatus:
24
+ running = 'running'
25
+ finish = 'finish'
23
26
 
24
27
  class FunctionResultStatus():
25
28
  host_name = socket.gethostname()
@@ -51,6 +54,7 @@ class FunctionResultStatus():
51
54
  self.time_cost = None
52
55
  self.time_end = None
53
56
  self.success = False
57
+ self.run_status = ''
54
58
  self.total_thread = threading.active_count()
55
59
  self._has_requeue = False
56
60
  self._has_to_dlx_queue = False
@@ -59,11 +63,14 @@ class FunctionResultStatus():
59
63
 
60
64
  def get_status_dict(self, without_datetime_obj=False):
61
65
  self.time_end = time.time()
62
- self.time_cost = round(self.time_end - self.time_start, 3)
63
- item ={}
64
- for k,v in self.__dict__.items():
66
+ if self.run_status == RunStatus.running:
67
+ self.time_cost = None
68
+ else:
69
+ self.time_cost = round(self.time_end - self.time_start, 3)
70
+ item = {}
71
+ for k, v in self.__dict__.items():
65
72
  if not k.startswith('_'):
66
- item[k] =v
73
+ item[k] = v
67
74
  item['host_name'] = self.host_name
68
75
  item['host_process'] = self.host_process
69
76
  item['script_name'] = self.script_name
@@ -119,7 +119,7 @@ def query_cols_view():
119
119
  @app.route('/query_result')
120
120
  @login_required
121
121
  def query_result_view():
122
- nb_print(request.values.to_dict())
122
+
123
123
  return jsonify(query_result(**request.values.to_dict()))
124
124
 
125
125
 
@@ -142,7 +142,7 @@ if __name__ == '__main__':
142
142
  # with app.test_request_context():
143
143
  # print(url_for('query_cols_view'))
144
144
 
145
- app.run(debug=False, threaded=True, host='0.0.0.0', port=27018)
145
+ app.run(debug=False, threaded=True, host='0.0.0.0', port=27019)
146
146
 
147
147
  '''
148
148
  linux 是export , win是 set
@@ -6,7 +6,7 @@ import json
6
6
  from pprint import pprint
7
7
  import time
8
8
  from flask import jsonify
9
-
9
+ import copy
10
10
  from funboost import nb_print
11
11
  from funboost.utils import time_util, decorators, LoggerMixin
12
12
  from funboost.utils.mongo_util import MongoMixin
@@ -36,6 +36,10 @@ def get_cols(col_name_search: str):
36
36
 
37
37
 
38
38
  def query_result(col_name, start_time, end_time, is_success, function_params: str, page, ):
39
+ query_kw = copy.copy(locals())
40
+ t0 = time.time()
41
+ if not col_name:
42
+ return []
39
43
  db = MongoMixin().mongo_db_task_status
40
44
  condition = {
41
45
  'insert_time': {'$gt': time_util.DatetimeConverter(start_time).datetime_obj,
@@ -56,7 +60,8 @@ def query_result(col_name, start_time, end_time, is_success, function_params: st
56
60
  # results = list(db.get_collection(col_name).find(condition, ).sort([('insert_time', -1)]).skip(int(page) * 100).limit(100))
57
61
  # with decorators.TimerContextManager():
58
62
  results = list(db.get_collection(col_name).find(condition, {'insert_time': 0, 'utime': 0}).skip(int(page) * 100).limit(100))
59
- # nb_print(result)
63
+ # nb_print(results)
64
+ nb_print(time.time() -t0, query_kw)
60
65
  return results
61
66
 
62
67
 
@@ -73,8 +78,8 @@ def get_speed(col_name, start_time, end_time):
73
78
  with decorators.TimerContextManager():
74
79
  # success_num = db.get_collection(col_name).count({**{'success': True}, **condition})
75
80
  # fail_num = db.get_collection(col_name).count({**{'success': False}, **condition})
76
- success_num = db.get_collection(col_name).count_documents({**{'success': True}, **condition})
77
- fail_num = db.get_collection(col_name).count_documents({**{'success': False}, **condition})
81
+ success_num = db.get_collection(col_name).count_documents({**{'success': True,'run_status':'finish'}, **condition})
82
+ fail_num = db.get_collection(col_name).count_documents({**{'success': False,'run_status':'finish'}, **condition})
78
83
  qps = (success_num + fail_num) / (time_util.DatetimeConverter(end_time).timestamp - time_util.DatetimeConverter(start_time).timestamp)
79
84
  return {'success_num': success_num, 'fail_num': fail_num, 'qps': round(qps, 1)}
80
85
 
@@ -123,7 +123,8 @@
123
123
 
124
124
 
125
125
  </main><!-- page-content" --></div><!-- page-wrapper -->
126
- <script src="{{ url_for('static',filename='js/jquery-1.11.0.min.js') }}" type="text/javascript"></script>
126
+ <!--<script src="{{ url_for('static',filename='js/jquery-1.11.0.min.js') }}" type="text/javascript"></script>-->
127
+ <script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
127
128
  <script src="http://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
128
129
 
129
130
 
@@ -163,6 +164,7 @@
163
164
  return year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
164
165
  }
165
166
 
167
+
166
168
  //昨天的时间
167
169
  var day1 = new Date();
168
170
  day1.setDate(day1.getDate() - 2);
@@ -220,16 +222,19 @@
220
222
  var html = ' <thead>\n' +
221
223
  ' <tr>\n' +
222
224
  ' <th>执行机器-进程-脚本</th>\n' +
223
- ' <th>函数执行完成时间</th>\n' +
225
+
224
226
  ' <th>函数名称</th>\n' +
225
227
  ' <th>函数入参</th>\n' +
226
228
  ' <th>函数结果</th>\n' +
227
- ' <th>消耗时间</th>\n' +
228
- ' <th>执行次数</th>\n' +
229
+ ' <th>消息发布时间</th>\n' +
230
+ ' <th>开始执行时间</th>\n' +
231
+ ' <th>消耗时间(秒)</th>\n' +
232
+ ' <th>执行次数(重试)</th>\n' +
233
+ ' <th>运行状态</th>\n' +
229
234
  ' <th>是否成功</th>\n' +
230
235
  ' <th>错误原因</th>\n' +
231
236
 
232
- ' <th>消息发布时间</th>\n' +
237
+
233
238
  ' <th>线程(协程)数</th>\n' +
234
239
  ' </tr>\n' +
235
240
  ' </thead>' +
@@ -257,11 +262,25 @@
257
262
  ' <td>{9}</td>\n' +
258
263
  ' <td>{10}</td>\n' +
259
264
  ' <td>{11}</td>\n' +
265
+ ' <td>{12}</td>\n' +
260
266
 
261
267
  ' </tr>';
262
268
  var successText = item.success === true ? "成功" : "失败";
263
- tr = tr.format(displayLevel, item.host_process + ' - ' + item.script_name, item.insert_time_str, item.function, item.params_str, item.result,
264
- item.time_cost, item.run_times, successText, item.exception, item.publish_time_str, item.total_thread);
269
+ <!-- console.info(item.run_status);-->
270
+ var run_status_text = item.run_status;
271
+ if (item.run_status==="running"){
272
+ successText = "未完成";
273
+ displayLevel = "info";
274
+ if ( Date.now() /1000 - item.time_start > 600) {
275
+ run_status_text = "running?";
276
+ }
277
+ }
278
+
279
+ var time_start_obj = new Date(item.time_start * 1000);
280
+ var time_start_str = dateToString(time_start_obj);
281
+
282
+ tr = tr.format(displayLevel, item.host_process + ' - ' + item.script_name, item.function, item.params_str, item.result,item.publish_time_str,
283
+ time_start_str,item.time_cost, item.run_times, run_status_text,successText, item.exception, item.total_thread);
265
284
  html += tr;
266
285
  }
267
286
  html += '</tbody>';
@@ -223,6 +223,13 @@ class AbstractPublisher(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
223
223
  self._init_count()
224
224
  return AsyncResult(task_id)
225
225
 
226
+ def send_msg(self,msg:typing.Union[dict,str]):
227
+ """直接发送任意消息内容到消息队列,不生成辅助参数,无视函数入参名字,不校验入参个数和键名"""
228
+ if isinstance(msg,dict):
229
+ msg = json.dumps(msg, ensure_ascii=False)
230
+ decorators.handle_exception(retry_times=10, is_throw_error=True, time_sleep=0.1)(
231
+ self.concrete_realization_of_publish)(msg)
232
+
226
233
  def push(self, *func_args, **func_kwargs):
227
234
  """
228
235
  简写,只支持传递消费函数的本身参数,不支持priority_control_config参数。
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: funboost
3
- Version: 42.3
3
+ Version: 42.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,4 +1,4 @@
1
- funboost/__init__.py,sha256=4L9vjt5plmQOlMBhI-YxdYx7SJaOiLohlY7XVV0fu0o,3766
1
+ funboost/__init__.py,sha256=5gHRofQPfikA7jOf5Hj1kucFcHajOIh_ChMQH_oIurw,3766
2
2
  funboost/__init__old.py,sha256=07A1MLsxLtuRQQOIfDyphddOwNBrGe34enoHWAnjV14,20379
3
3
  funboost/__main__.py,sha256=-6Nogi666Y0LN8fVm3JmHGTOk8xEGWvotW_GDbSaZME,1065
4
4
  funboost/constant.py,sha256=haAbx2cvTN9itPzBG4v3_ODIi1-RudvBj6s_QjniqjU,7162
@@ -33,7 +33,7 @@ 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=T-BgSzf3ttOBBtPbjb5g0sewzZOcXEpzpTzMTUdHfwk,72942
36
+ funboost/consumers/base_consumer.py,sha256=qgy9M8ibPl2GFI4JLsRDSPLZTNyoIaxRG4tjSzmroVw,72875
37
37
  funboost/consumers/celery_consumer.py,sha256=W25gbGyimf8KG5lLbtgar3Ix7F3O4cIRBLtRq8nJ0AE,9216
38
38
  funboost/consumers/confirm_mixin.py,sha256=eY6fNwx51Hn4bQSYRjyTRwOqfCGsikVnd2Ga_Ep31N4,6062
39
39
  funboost/consumers/dramatiq_consumer.py,sha256=ozmeAfeF0U-YNYHK4suQB0N264h5AZdfMH0O45Mh-8A,2229
@@ -81,12 +81,12 @@ funboost/contrib/redis_consume_latest_msg_broker.py,sha256=ESortBZ2qu_4PBCa3e3Fe
81
81
  funboost/contrib/save_result_status_to_sqldb.py,sha256=AxvD7nHs4sjr9U0kwEZzyPKrsGdU_JzEgzzhh_V1_4w,4071
82
82
  funboost/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
83
83
  funboost/core/active_cousumer_info_getter.py,sha256=09fEc-BTEIRfDDfHmOvKnMjLjtOyp4edLsUlAXUR_Qs,4966
84
- funboost/core/booster.py,sha256=s7FNcKiGsTM6TEkcVO9EjQ0rfWL3XGN3yvpRAN7CGgI,13259
84
+ funboost/core/booster.py,sha256=k6UPxfW7QdhfdVu9yprHkF46jLO2eXTqTZPYkukmyZc,15741
85
85
  funboost/core/exceptions.py,sha256=pLF7BkRJAfDiWp2_xGZqencmwdPiSQI1NENbImExknY,1311
86
86
  funboost/core/fabric_deploy_helper.py,sha256=KPjifNy1G1tDOT2eaR0X8hegot0HUk5vF-P1DnhxME4,8941
87
87
  funboost/core/func_params_model.py,sha256=jVPWke_UpwZ_Ik28_dL_j8h2dSrtYlEFTtUWMIw2KCA,17594
88
88
  funboost/core/function_result_status_config.py,sha256=PyjqAQOiwsLt28sRtH-eYRjiI3edPFO4Nde0ILFRReE,1764
89
- funboost/core/function_result_status_saver.py,sha256=Vw9f7YnLUb1xycPCa1aatzGOP21lOJgY7Diz03cqMKI,8969
89
+ funboost/core/function_result_status_saver.py,sha256=UdokGSwU630t70AZnT9Ecj7GpYXORBDivlc9kadoI2E,9172
90
90
  funboost/core/helper_funs.py,sha256=M9Ad9EzgHdP581X-vuFgCavJRoezLGXlXSFg7zyMWD0,1578
91
91
  funboost/core/kill_remote_task.py,sha256=MZ5vWLGt6SxyN76h5Lf_id9tyVUzjR-qXNyJwXaGlZY,8129
92
92
  funboost/core/loggers.py,sha256=173aXdqE8nAe8t6OcVMNAFsCUClVrWQovdQhTAg9IyM,2407
@@ -94,17 +94,17 @@ funboost/core/msg_result_getter.py,sha256=oZDuLDR5XQNzzvgDTsA7wroICToPwrkU9-OAaX
94
94
  funboost/core/muliti_process_enhance.py,sha256=0wgy8qnxfg_g-BtlKfysH6TZ9s97EWTdLFVWPAVUGw0,3601
95
95
  funboost/core/try_get_user_funboost_common_config.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
96
96
  funboost/core/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
97
- funboost/core/cli/discovery_boosters.py,sha256=G23pwJDNi5iQnkgOEzMlioaK-rPCaMx3RJpAcTT1_9g,2930
98
- funboost/core/cli/funboost_cli_user_templ.py,sha256=vII8IELLhlYpHZmfUsdt-UE699tOSBugkiFl90sOLKo,2109
99
- funboost/core/cli/funboost_fire.py,sha256=zqWYH4OCFJ8ynOkgNAhcqQwgCAjLH63TlhCRyJREXFA,5413
97
+ funboost/core/cli/discovery_boosters.py,sha256=68SUEQnN3KN8_mfLHN2ho1z02vHAA-gHhTGfUAf4kz8,3811
98
+ funboost/core/cli/funboost_cli_user_templ.py,sha256=XUpKLxRKtYfebPUM8wii64kB0HW8L7j9LnRpT0xCfQI,2243
99
+ funboost/core/cli/funboost_fire.py,sha256=OT0SNi9Zb0Tom2E0cWuArQs0obUowAA_rpCF7GdaKPs,5065
100
100
  funboost/factories/__init__.py,sha256=s7kKKjR1HU5eMjPD6r5b-SXTVMo1zBp2JjOAtkyt5Yo,178
101
101
  funboost/factories/broker_kind__publsiher_consumer_type_map.py,sha256=2fWuNVDOYbs8CCrQnQtWIc3wwQ5a9AOFEd7-cufj3I8,9630
102
102
  funboost/factories/consumer_factory.py,sha256=rPceMsUr2mrcFXL-_3kQGknNiADjfgTh9wXG1qd8yAw,1041
103
103
  funboost/factories/publisher_factotry.py,sha256=JOvECeovdDRXWvh_dqnNoXX-A3M9vUjVRMCpaCl_R_Q,2040
104
- funboost/function_result_web/app.py,sha256=xrSldlZRt0OrnRAI22IS9PJa5nFMwDrKicelIHnfbLo,5013
105
- funboost/function_result_web/functions.py,sha256=OIPMxc4jv51qnhBxFGfTZnpMx5p4lQflPoTviDTbJUc,7345
104
+ funboost/function_result_web/app.py,sha256=DhUZFi083KILEc5WGCGkuYQ9fiHa8nB6curt6TSa7EQ,4975
105
+ funboost/function_result_web/functions.py,sha256=dXGUD9H62RdE6DN53tVm16tjEUNLD52Sg9YC5Loh6G4,7541
106
106
  funboost/function_result_web/__pycache__/app.cpython-37.pyc,sha256=p-jwU7xf31KOJhmhNXqj6J79PTxjMbiTU16gAotpSEw,4045
107
- funboost/function_result_web/__pycache__/functions.cpython-37.pyc,sha256=zcGoygKR-or6zr-Qt3ICqkw_d5HGvzFobq--h40M5Po,3982
107
+ funboost/function_result_web/__pycache__/functions.cpython-37.pyc,sha256=vEXI6a8iSONHTW49VOpm9kaaoW4xGuP4JpxlrIXHHzs,4117
108
108
  funboost/function_result_web/static/assets/css/custom.css,sha256=3brvjy2aBOTIXcTUK4NV6dX5wFRqx6K2aLu_jQn63jM,7674
109
109
  funboost/function_result_web/static/assets/css/jquery.mCustomScrollbar.min.css,sha256=JHGEmB629pipTkMag9aMaw32I8zle24p3FpsEeI6oZU,42839
110
110
  funboost/function_result_web/static/assets/img/user.jpg,sha256=Vz1A99gho-0bKV67Pt2s_zT25mWhNcPe0mWG-0mRl9U,23610
@@ -116,10 +116,10 @@ funboost/function_result_web/static/images/password.png,sha256=0jRivuQAhWKtkS73p
116
116
  funboost/function_result_web/static/images/tick.png,sha256=S9dZYN4HQzw7JsWPw3ut1dQp4OTJ_Uh2Qp2KUDF1Jv8,2912
117
117
  funboost/function_result_web/static/images/user.png,sha256=HxLjNc83WZzZEscZRdmVhGKlPXNdp_EKmmYxafuyb3g,622
118
118
  funboost/function_result_web/static/js/jquery-1.11.0.min.js,sha256=ryQZ3RXgnqkTz-lNEw-YcEhnMuV3ZODwLqOEbyBBRu4,96383
119
- funboost/function_result_web/templates/index.html,sha256=ubxUxouCOHHCZbeSnRdQ2auKhQ49eR--9NJ922eVRH8,19520
119
+ funboost/function_result_web/templates/index.html,sha256=YM0582Q4t2da-xBf3Ga0McIfcsT9H98rjZck-irMkGo,20387
120
120
  funboost/function_result_web/templates/login.html,sha256=q37dj7O0LeyiV38Zd5P1Qn_qmhjdFomuYTRY1Yk48Bo,2007
121
121
  funboost/publishers/__init__.py,sha256=xqBHlvsJQVPfbdvP84G0LHmVB7-pFBS7vDnX1Uo9pVY,131
122
- funboost/publishers/base_publisher.py,sha256=JUMZsAaaMHJfMlfBKelgowbY6-McDGB0tkYORHigOZ0,14515
122
+ funboost/publishers/base_publisher.py,sha256=sWpSDG5BfUrI7wTQ-3FX_dqaHXL5Or8axcmLAglUEG0,14944
123
123
  funboost/publishers/celery_publisher.py,sha256=uc9N1uLW74skUCw8dsnvxORM2O3cy4SiI7tUZRmvkHA,2336
124
124
  funboost/publishers/celery_publisher000.py,sha256=2XLOyU2__vlIUTi5L15uf0BJqAIjxbc3kCLIRDSOY9w,3966
125
125
  funboost/publishers/confluent_kafka_publisher.py,sha256=gC4SUk6I_7zjSngcbTI7oTJ7sza3oE3PE19KQkwCpn4,4802
@@ -261,9 +261,9 @@ funboost/utils/pysnooper_ydf/utils.py,sha256=evSmGi_Oul7vSP47AJ0DLjFwoCYCfunJZ1m
261
261
  funboost/utils/pysnooper_ydf/variables.py,sha256=QejRDESBA06KG9OH4sBT4J1M55eaU29EIHg8K_igaXo,3693
262
262
  funboost/utils/times/__init__.py,sha256=Y4bQD3SIA_E7W2YvHq2Qdi0dGM4H2DxyFNdDOuFOq1w,2417
263
263
  funboost/utils/times/version.py,sha256=11XfnZVVzOgIhXXdeN_mYfdXThfrsbQHpA0wCjz-hpg,17
264
- funboost-42.3.dist-info/LICENSE,sha256=9EPP2ktG_lAPB8PjmWV-c9BiaJHc_FP6pPLcUrUwx0E,11562
265
- funboost-42.3.dist-info/METADATA,sha256=LFWWfIZjcOJmoiKXrhzg5rPfE9dwYBOGZmsCiwgsYSQ,30477
266
- funboost-42.3.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
267
- funboost-42.3.dist-info/entry_points.txt,sha256=yMSSAGRzRAAhGyNNQHw24MooKlDZsaJ499_D6fPl58A,96
268
- funboost-42.3.dist-info/top_level.txt,sha256=K8WuKnS6MRcEWxP1NvbmCeujJq6TEfbsB150YROlRw0,9
269
- funboost-42.3.dist-info/RECORD,,
264
+ funboost-42.6.dist-info/LICENSE,sha256=9EPP2ktG_lAPB8PjmWV-c9BiaJHc_FP6pPLcUrUwx0E,11562
265
+ funboost-42.6.dist-info/METADATA,sha256=LJFS2m_BYI8k0nOIAYowA5S8WquCeKqz-lULFs-M5uM,30477
266
+ funboost-42.6.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
267
+ funboost-42.6.dist-info/entry_points.txt,sha256=yMSSAGRzRAAhGyNNQHw24MooKlDZsaJ499_D6fPl58A,96
268
+ funboost-42.6.dist-info/top_level.txt,sha256=K8WuKnS6MRcEWxP1NvbmCeujJq6TEfbsB150YROlRw0,9
269
+ funboost-42.6.dist-info/RECORD,,