funboost 48.7__py3-none-any.whl → 48.8__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.

Files changed (34) hide show
  1. funboost/__init__.py +1 -1
  2. funboost/__main__.py +2 -0
  3. funboost/constant.py +2 -1
  4. funboost/consumers/base_consumer.py +4 -3
  5. funboost/consumers/rabbitmq_amqpstorm_consumer.py +1 -1
  6. funboost/core/active_cousumer_info_getter.py +3 -3
  7. funboost/core/booster.py +1 -1
  8. funboost/core/cli/funboost_fire.py +10 -0
  9. funboost/core/msg_result_getter.py +1 -0
  10. funboost/function_result_web/__pycache__/app.cpython-37.pyc +0 -0
  11. funboost/function_result_web/__pycache__/app.cpython-39.pyc +0 -0
  12. funboost/function_result_web/__pycache__/functions.cpython-37.pyc +0 -0
  13. funboost/function_result_web/__pycache__/functions.cpython-39.pyc +0 -0
  14. funboost/function_result_web/app.py +42 -2
  15. funboost/function_result_web/app_debug_start.py +6 -0
  16. funboost/function_result_web/functions.py +57 -3
  17. funboost/function_result_web/static/js_cdn/tabulator-tables@5.5.0/dist/js/tabulator.min.js +1 -1
  18. funboost/function_result_web/templates/about.html +0 -9
  19. funboost/function_result_web/templates/conusme_speed.html +2 -2
  20. funboost/function_result_web/templates/fun_result_table.html +1 -1
  21. funboost/function_result_web/templates/index.html +34 -9
  22. funboost/function_result_web/templates/queue_op.html +1 -1
  23. funboost/function_result_web/templates/rpc_call.html +298 -0
  24. funboost/function_result_web/templates/running_consumer_by_ip.html +2 -2
  25. funboost/function_result_web/templates/running_consumer_by_queue_name.html +2 -2
  26. funboost/utils/ctrl_c_end.py +19 -1
  27. funboost/utils/dependency_packages_in_pythonpath/aioredis/readme.md +6 -0
  28. funboost/utils/dependency_packages_in_pythonpath/readme.md +6 -0
  29. {funboost-48.7.dist-info → funboost-48.8.dist-info}/METADATA +7 -3
  30. {funboost-48.7.dist-info → funboost-48.8.dist-info}/RECORD +34 -32
  31. {funboost-48.7.dist-info → funboost-48.8.dist-info}/LICENSE +0 -0
  32. {funboost-48.7.dist-info → funboost-48.8.dist-info}/WHEEL +0 -0
  33. {funboost-48.7.dist-info → funboost-48.8.dist-info}/entry_points.txt +0 -0
  34. {funboost-48.7.dist-info → funboost-48.8.dist-info}/top_level.txt +0 -0
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__ = "48.7"
16
+ __version__ = "48.8"
17
17
 
18
18
  from funboost.set_frame_config import show_frame_config
19
19
 
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
  '''
funboost/constant.py CHANGED
@@ -112,4 +112,5 @@ class ConstStrForClassMethod:
112
112
  class RedisKeys:
113
113
  REDIS_KEY_PAUSE_FLAG = 'funboost_pause_flag'
114
114
  REDIS_KEY_STOP_FLAG = 'funboost_stop_flag'
115
- QUEUE__MSG_COUNT_MAP = 'funboost_queue__msg_count_map'
115
+ QUEUE__MSG_COUNT_MAP = 'funboost_queue__msg_count_map'
116
+ FUNBOOST_QUEUE__CONSUMER_PARAMS= 'funboost_queue__consumer_parmas'
@@ -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 # 每单位时间执行了多少次任务失败。
@@ -836,8 +837,8 @@ class AbstractConsumer(LoggerLevelSetterMixin, metaclass=abc.ABCMeta, ):
836
837
  if (current_function_result_status.success is False and current_retry_times == max_retry_times) or current_function_result_status.success is True:
837
838
  await simple_run_in_executor(push_result)
838
839
 
839
- # 异步执行不存在线程并发,不需要加锁。
840
- self.metric_calculation.cal(t_start_run_fun, current_function_result_status)
840
+ async with self._async_lock_for_count_execute_task_times_every_unit_time:
841
+ self.metric_calculation.cal(t_start_run_fun, current_function_result_status)
841
842
 
842
843
  self.user_custom_record_process_info_func(current_function_result_status) # 两种方式都可以自定义,记录结果.建议使用文档4.21.b的方式继承来重写
843
844
  await self.aio_user_custom_record_process_info_func(current_function_result_status)
@@ -1175,7 +1176,7 @@ class MetricCalculation:
1175
1176
  self.consumer._distributed_consumer_statistics.active_consumer_num)
1176
1177
  msg += f''' 预计还需要 {need_time} 时间 才能执行完成 队列 {self.consumer.queue_name} 中的 {self.msg_num_in_broker} 个剩余任务'''
1177
1178
  self.consumer.logger.info(msg)
1178
- self.last_show_remaining_execution_time = time.time()
1179
+ self.last_show_remaining_execution_time = time.time()
1179
1180
  self.current_time_for_execute_task_times_every_unit_time = time.time()
1180
1181
  self.consuming_function_cost_time_total_every_unit_time_tmp = 0
1181
1182
  self.execute_task_times_every_unit_time_temp = 0
@@ -42,5 +42,5 @@ class RabbitmqConsumerAmqpStorm(AbstractConsumer):
42
42
 
43
43
  def _requeue(self, kw):
44
44
  # amqpstorm.Message.delivery_tag
45
- print(kw['amqpstorm_message'].delivery_tag)
45
+ # print(kw['amqpstorm_message'].delivery_tag)
46
46
  kw['amqpstorm_message'].nack(requeue=True)
@@ -104,12 +104,12 @@ class QueueConusmerParamsGetter(RedisMixin, FunboostFileLoggerMixin):
104
104
  queue__pause_map = self.redis_db_frame.hgetall(RedisKeys.REDIS_KEY_PAUSE_FLAG)
105
105
  return {k:int(v) for k,v in queue__pause_map.items()}
106
106
 
107
- def get_msg_num(self):
107
+ def get_msg_num(self,ignore_report_ts=False):
108
108
  queue__msg_count_info_map = self.redis_db_frame.hgetall(RedisKeys.QUEUE__MSG_COUNT_MAP)
109
109
  queue__msg_count_dict = {}
110
110
  for queue_name,info_json in queue__msg_count_info_map.items():
111
111
  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:
112
+ if ignore_report_ts or (info_dict['report_ts'] > time.time() - 15 and info_dict['last_get_msg_num_ts'] > time.time() - 1200):
113
113
  queue__msg_count_dict[queue_name] = info_dict['msg_num_in_broker']
114
114
  return queue__msg_count_dict
115
115
 
@@ -127,7 +127,7 @@ class QueueConusmerParamsGetter(RedisMixin, FunboostFileLoggerMixin):
127
127
  queue__active_consumers_map = ActiveCousumerProcessInfoGetter().get_all_hearbeat_info_partition_by_queue_name()
128
128
  queue__consumer_params_map = self.get_queue_params()
129
129
  queue__pause_map = self.get_pause_flag()
130
- queue__msg_count_dict = self.get_msg_num()
130
+ queue__msg_count_dict = self.get_msg_num(ignore_report_ts=True)
131
131
  queue_params_and_active_consumers = {}
132
132
 
133
133
  for queue, consumer_params in queue__consumer_params_map.items():
funboost/core/booster.py CHANGED
@@ -307,7 +307,7 @@ class BoostersManager:
307
307
  跨不同的项目,发布消息。例如proj1中定义有fun1消费函数,但proj2无法直接到日proj1的函数,无法直接 fun1.push 来发布消息
308
308
  可以使用这个方法,获取一个publisher。
309
309
 
310
- publisher = BoostersManager.get_cross_project_publisher(PublisherParams(queue_name='proj1_queue', broker_kind=BrokerEnum.SQLITE_QUEUE))
310
+ publisher = BoostersManager.get_cross_project_publisher(PublisherParams(queue_name='proj1_queue', broker_kind=publisher_params.broker_kind))
311
311
  publisher.publish({'x': aaa})
312
312
  """
313
313
  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
@@ -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:
@@ -12,6 +12,9 @@ import os
12
12
 
13
13
  import datetime
14
14
  import json
15
+ import traceback
16
+
17
+ from funboost.core.func_params_model import PriorityConsumingControlConfig
15
18
 
16
19
  """
17
20
  pip install Flask flask_bootstrap flask_wtf wtforms flask_login
@@ -26,6 +29,7 @@ from flask_login import login_user, logout_user, login_required, LoginManager, U
26
29
  import nb_log
27
30
  from funboost import nb_print,ActiveCousumerProcessInfoGetter,BoostersManager,PublisherParams,RedisMixin
28
31
  from funboost.function_result_web.functions import get_cols, query_result, get_speed, Statistic
32
+ from funboost.function_result_web import functions as app_functions
29
33
  from funboost.core.active_cousumer_info_getter import QueueConusmerParamsGetter
30
34
  from funboost.constant import RedisKeys
31
35
 
@@ -119,7 +123,8 @@ def logout():
119
123
  @app.route('/')
120
124
  @login_required
121
125
  def index():
122
- return render_template('index.html')
126
+ page = request.args.get('page')
127
+ return render_template('index.html', page=page)
123
128
 
124
129
 
125
130
  @app.route('/query_cols')
@@ -238,6 +243,39 @@ def resume_consume(queue_name):
238
243
  RedisMixin().redis_db_frame.hset(RedisKeys.REDIS_KEY_PAUSE_FLAG, queue_name,'0')
239
244
  return jsonify({'success':True})
240
245
 
246
+ @app.route('/queue/get_msg_num',methods=['GET'])
247
+ def get_msg_num():
248
+ return jsonify(QueueConusmerParamsGetter().get_msg_num(ignore_report_ts=True))
249
+
250
+ @app.route('/rpc/rpc_call',methods=['POST'])
251
+ def rpc_call():
252
+ """
253
+ class MsgItem(BaseModel):
254
+ queue_name: str # 队列名
255
+ msg_body: dict # 消息体,就是boost函数的入参字典,例如 {"x":1,"y":2}
256
+ need_result: bool = False # 发布消息后,是否需要返回结果
257
+ timeout: int = 60 # 等待结果返回的最大等待时间.
258
+
259
+
260
+ class PublishResponse(BaseModel):
261
+ succ: bool
262
+ msg: str
263
+ status_and_result: typing.Optional[dict] = None # 消费函数的消费状态和结果.
264
+ task_id:str
265
+ """
266
+
267
+ msg_item = request.get_json()
268
+ return jsonify(app_functions.rpc_call(**msg_item))
269
+
270
+ @app.route('/rpc/get_result_by_task_id',methods=['GET'])
271
+ def get_result_by_task_id():
272
+ res = app_functions.get_result_by_task_id(task_id=request.args.get('task_id'),
273
+ timeout=request.args.get('timeout') or 60)
274
+ if res['status_and_result'] is None:
275
+ return jsonify({'succ':False,'msg':'task_id不存在或者超时或者结果已经过期'})
276
+ return jsonify(res)
277
+
278
+
241
279
  def start_funboost_web_manager(host='0.0.0.0', port=27018,block=False):
242
280
  print('start_funboost_web_manager , sys.path :', sys.path)
243
281
  def _start_funboost_web_manager():
@@ -246,7 +284,9 @@ def start_funboost_web_manager(host='0.0.0.0', port=27018,block=False):
246
284
  _start_funboost_web_manager()
247
285
  else:
248
286
  threading.Thread(target=_start_funboost_web_manager).start()
249
-
287
+
288
+
289
+
250
290
  if __name__ == '__main__':
251
291
  # app.jinja_env.auto_reload = True
252
292
  # with app.test_request_context():
@@ -0,0 +1,6 @@
1
+ from funboost.function_result_web.app import app
2
+
3
+
4
+ if __name__ == '__main__':
5
+ app.run(debug=True, threaded=True, host='0.0.0.0', port=27018)
6
+
@@ -6,9 +6,16 @@ import json
6
6
  from pprint import pprint
7
7
  import time
8
8
  import copy
9
+ import traceback
9
10
  from funboost import nb_print
11
+ from funboost.constant import RedisKeys
12
+ from funboost.core.booster import BoostersManager
13
+ from funboost.core.func_params_model import PriorityConsumingControlConfig, PublisherParams
14
+ from funboost.core.msg_result_getter import AsyncResult
15
+ from funboost.core.serialization import Serialization
10
16
  from funboost.utils import time_util, decorators, LoggerMixin
11
17
  from funboost.utils.mongo_util import MongoMixin
18
+ from funboost.utils.redis_manager import RedisMixin
12
19
 
13
20
  # from test_frame.my_patch_frame_config import do_patch_frame_config
14
21
  #
@@ -144,6 +151,46 @@ class Statistic(LoggerMixin):
144
151
  t2.strftime('%Y-%m-%d %H:%M:%S'))
145
152
  self.result['recent_60_seconds']['count_arr'].append(count)
146
153
 
154
+ def rpc_call(queue_name, msg_body, need_result, timeout):
155
+
156
+ status_and_result = None
157
+ task_id = None
158
+ try:
159
+ boost_params_json = RedisMixin().redis_db_frame.hget(RedisKeys.FUNBOOST_QUEUE__CONSUMER_PARAMS,queue_name)
160
+ boost_params_dict = Serialization.to_dict(boost_params_json)
161
+ broker_kind = boost_params_dict['broker_kind']
162
+ publisher = BoostersManager.get_cross_project_publisher(PublisherParams(queue_name=queue_name,
163
+ broker_kind=broker_kind,
164
+ publish_msg_log_use_full_msg=True))
165
+
166
+ if need_result:
167
+ # if booster.boost_params.is_using_rpc_mode is False:
168
+ # raise ValueError(f' need_result 为true,{booster.queue_name} 队列消费者 需要@boost设置支持rpc模式')
169
+
170
+ async_result = publisher.publish(msg_body,priority_control_config=PriorityConsumingControlConfig(is_using_rpc_mode=True))
171
+ async_result.set_timeout(timeout)
172
+ status_and_result = async_result.status_and_result
173
+ # print(status_and_result)
174
+ task_id = async_result.task_id
175
+ else:
176
+ async_result =publisher.publish(msg_body)
177
+ task_id = async_result.task_id
178
+ return dict(succ=True, msg=f'{queue_name} 队列,消息发布成功',
179
+ status_and_result=status_and_result,task_id=task_id)
180
+ except Exception as e:
181
+ return dict(succ=False, msg=f'{queue_name} 队列,消息发布失败 {type(e)} {e} {traceback.format_exc()}',
182
+ status_and_result=status_and_result,task_id=task_id)
183
+
184
+
185
+ def get_result_by_task_id(task_id,timeout):
186
+ async_result = AsyncResult(task_id)
187
+ async_result.set_timeout(timeout)
188
+ status_and_result = async_result.status_and_result
189
+ return dict(succ=True, msg=f'task_id:{task_id} 获取结果成功',
190
+ status_and_result=status_and_result,task_id=task_id)
191
+
192
+
193
+
147
194
 
148
195
  if __name__ == '__main__':
149
196
  # print(get_cols('4'))
@@ -152,6 +199,13 @@ if __name__ == '__main__':
152
199
  # nb_print(get_speed_last_minute('queue_test54'))
153
200
 
154
201
  # nb_print(get_speed('queue_test56', '2019-09-18 16:03:29', '2019-09-23 16:03:29'))
155
- stat = Statistic('queue_test_f01t')
156
- stat.build_result()
157
- nb_print(stat.result)
202
+ # stat = Statistic('queue_test_f01t')
203
+ # stat.build_result()
204
+ # nb_print(stat.result)
205
+
206
+ # res = rpc_call('queue_test_g02t',{'x':1,'y':2},True,60)
207
+
208
+ res = get_result_by_task_id('3232',60)
209
+ print(res)
210
+
211
+