funboost 47.9__py3-none-any.whl → 48.1__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 +3 -3
- funboost/assist/celery_helper.py +1 -1
- funboost/constant.py +7 -0
- funboost/consumers/base_consumer.py +132 -75
- funboost/consumers/redis_consumer_ack_able.py +1 -1
- funboost/core/active_cousumer_info_getter.py +60 -0
- funboost/core/current_task.py +37 -0
- funboost/core/func_params_model.py +2 -2
- funboost/core/function_result_status_saver.py +1 -1
- 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 +104 -7
- funboost/function_result_web/functions.py +17 -4
- funboost/function_result_web/static/css/content_page_style.css +39 -0
- funboost/function_result_web/static/images/favicon.ico +0 -0
- funboost/function_result_web/static/js/bootstrap-datetimepicker.min.js +2 -0
- funboost/function_result_web/static/js/echarts.min.js +32478 -0
- funboost/function_result_web/static/js/moment-with-locales.min.js +1 -0
- funboost/function_result_web/static/js/select2.min.js +2 -0
- funboost/function_result_web/templates/about.html +67 -0
- funboost/function_result_web/templates/conusme_speed.html +217 -0
- funboost/function_result_web/templates/fun_result_table.html +433 -0
- funboost/function_result_web/templates/index.html +194 -423
- funboost/function_result_web/templates/index_backup.html +475 -0
- 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 +153 -0
- funboost/function_result_web/templates/queue_op.html +490 -0
- funboost/function_result_web/templates/running_consumer_by_ip.html +220 -0
- funboost/function_result_web/templates/running_consumer_by_queue_name.html +216 -0
- funboost/timing_job/__init__.py +3 -218
- funboost/timing_job/apscheduler_use_redis_store.py +6 -1
- funboost/timing_job/timing_job_base.py +213 -0
- funboost/timing_job/timing_push.py +136 -0
- funboost/utils/ctrl_c_end.py +1 -1
- {funboost-47.9.dist-info → funboost-48.1.dist-info}/METADATA +78 -76
- {funboost-47.9.dist-info → funboost-48.1.dist-info}/RECORD +39 -22
- {funboost-47.9.dist-info → funboost-48.1.dist-info}/WHEEL +1 -1
- {funboost-47.9.dist-info → funboost-48.1.dist-info}/LICENSE +0 -0
- {funboost-47.9.dist-info → funboost-48.1.dist-info}/entry_points.txt +0 -0
- {funboost-47.9.dist-info → funboost-48.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
8
|
+
<title>pytho万能分布式函数调度框架</title>
|
|
9
|
+
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
|
|
10
|
+
<link href="http://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
|
11
|
+
<link rel="stylesheet"
|
|
12
|
+
href="https://cdn.bootcss.com/bootstrap-datetimepicker/4.17.47/css/bootstrap-datetimepicker.min.css">
|
|
13
|
+
<link rel="stylesheet" href="{{ url_for('static',filename='assets/css/jquery.mCustomScrollbar.min.css') }}">
|
|
14
|
+
<link rel="stylesheet" href="{{ url_for('static',filename='assets/css/custom.css') }}">
|
|
15
|
+
|
|
16
|
+
<!-- 在其他 link 标签后添加 -->
|
|
17
|
+
<link href="https://cdn.bootcdn.net/ajax/libs/select2/4.0.13/css/select2.min.css" rel="stylesheet">
|
|
18
|
+
<link href="{{ url_for('static',filename='css/content_page_style.css') }}" rel="stylesheet">
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
<script src="{{ url_for('static',filename='js/jquery-1.11.0.min.js') }}" type="text/javascript"></script>
|
|
22
|
+
<!-- <script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.11.0/jquery.min.js"></script> -->
|
|
23
|
+
<!-- 在其他 script 标签后添加 -->
|
|
24
|
+
<!-- <script src="https://cdn.bootcdn.net/ajax/libs/select2/4.0.13/js/select2.min.js"></script> -->
|
|
25
|
+
<script src="{{ url_for('static',filename='/js/select2.min.js') }}"></script>
|
|
26
|
+
<script src="http://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
<script src="{{ url_for('static',filename='js/moment-with-locales.min.js') }}"></script>
|
|
30
|
+
<script src="{{ url_for('static',filename='js/bootstrap-datetimepicker.min.js') }}"></script>
|
|
31
|
+
<!-- <script src="https://cdn.bootcss.com/bootstrap-datetimepicker/4.17.47/js/bootstrap-datetimepicker.min.js"></script> -->
|
|
32
|
+
<!-- <script type="text/javascript" src="https://cdn.bootcss.com/echarts/3.3.0/echarts.js"></script> -->
|
|
33
|
+
<script type="text/javascript" src="{{ url_for('static',filename='js/echarts.min.js') }}"></script>
|
|
34
|
+
|
|
35
|
+
<script src="{{ url_for('static',filename='assets/js/jquery.mCustomScrollbar.concat.min.js') }}"></script>
|
|
36
|
+
<script src="{{ url_for('static',filename='assets/js/custom.js') }}"></script>
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
<!-- 添加 Tabulator 样式和脚本 -->
|
|
40
|
+
<link href="https://unpkg.com/tabulator-tables@5.5.0/dist/css/tabulator.min.css" rel="stylesheet">
|
|
41
|
+
<link href="https://unpkg.com/tabulator-tables@5.5.0/dist/css/tabulator_bootstrap3.min.css" rel="stylesheet">
|
|
42
|
+
<script type="text/javascript" src="https://unpkg.com/tabulator-tables@5.5.0/dist/js/tabulator.min.js"></script>
|
|
43
|
+
|
|
44
|
+
<style>
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
</style>
|
|
48
|
+
</head>
|
|
49
|
+
|
|
50
|
+
<body>
|
|
51
|
+
|
|
52
|
+
<div class="container-fluid" style="margin-top: 5px;">
|
|
53
|
+
<div style="margin-top: 5px;">
|
|
54
|
+
<form class="form-inline" role="form" style="">
|
|
55
|
+
<div class="form-group ">
|
|
56
|
+
<label for="col_name_search">host:</label>
|
|
57
|
+
<select class="form-control" id="col_name_search">
|
|
58
|
+
<option value="">请选择ip...</option>
|
|
59
|
+
</select>
|
|
60
|
+
</div>
|
|
61
|
+
<button type="button" class="btn btn-default marginLeft20" onclick="query()">查询</button>
|
|
62
|
+
</form>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<div id="result-table" style="margin-top: 20px;"></div>
|
|
66
|
+
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
<script>
|
|
75
|
+
|
|
76
|
+
// 在现有的变量声明后添加
|
|
77
|
+
var allQueues = []; // 存储所有队列数据
|
|
78
|
+
var currentColName;
|
|
79
|
+
|
|
80
|
+
// 页面加载完成后立即获取所有队列
|
|
81
|
+
$(document).ready(function () {
|
|
82
|
+
$.ajax({
|
|
83
|
+
url: "{{ url_for('hearbeat_info_partion_by_ip')}}",
|
|
84
|
+
data: { col_name_search: '' },
|
|
85
|
+
async: true,
|
|
86
|
+
success: function (result) {
|
|
87
|
+
allQueues = result;
|
|
88
|
+
var html = '<option value="">请选择ip...</option>';
|
|
89
|
+
for (var item of result) {
|
|
90
|
+
html += '<option value="' + item.collection_name + '">' +
|
|
91
|
+
item.collection_name + ' (' + item.count + ')</option>';
|
|
92
|
+
}
|
|
93
|
+
$("#col_name_search").html(html);
|
|
94
|
+
|
|
95
|
+
// 初始化选择框的搜索功能
|
|
96
|
+
$("#col_name_search").select2({
|
|
97
|
+
placeholder: "请输入ip名称搜索...",
|
|
98
|
+
allowClear: true,
|
|
99
|
+
width: '300px'
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// 监听选择变化
|
|
103
|
+
$("#col_name_search").on('change', function () {
|
|
104
|
+
var selectedQueue = $(this).val();
|
|
105
|
+
console.log("Selected queue:", selectedQueue);
|
|
106
|
+
currentColName = selectedQueue;
|
|
107
|
+
// if(selectedQueue) {
|
|
108
|
+
// queryResult(selectedQueue, 0, true);
|
|
109
|
+
// }
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
$(document).ready(function (){
|
|
116
|
+
query()
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
function query() {
|
|
121
|
+
$.ajax({
|
|
122
|
+
url: "{{ url_for('hearbeat_info_by_ip')}}",
|
|
123
|
+
data: { ip: currentColName },
|
|
124
|
+
async: true,
|
|
125
|
+
success: function (result) {
|
|
126
|
+
console.info(result);
|
|
127
|
+
|
|
128
|
+
// 创建表格
|
|
129
|
+
var table = new Tabulator("#result-table", {
|
|
130
|
+
theme: "bootstrap3",
|
|
131
|
+
data: result,
|
|
132
|
+
// layout: "fitColumns",
|
|
133
|
+
layout: "fitDataTable", // 改为 fitDataTable
|
|
134
|
+
responsiveLayout: false, // 禁用响应式布局
|
|
135
|
+
columns: [
|
|
136
|
+
{title: "<br><br>队列名称", field: "queue_name","width":200},
|
|
137
|
+
{title: "<br><br>消费函数", field: "consuming_function"},
|
|
138
|
+
{title: "<br><br>主机名", field: "computer_name"},
|
|
139
|
+
{title: "<br><br>IP地址", field: "computer_ip"},
|
|
140
|
+
{title: "<br><br>进程ID", field: "process_id"},
|
|
141
|
+
{title: "<br><br>启动时间", field: "start_datetime_str","width":200},
|
|
142
|
+
{title: "<br><br>最近心跳时间", field: "hearbeat_datetime_str","width":200},
|
|
143
|
+
|
|
144
|
+
{title:"近10秒<br>运行完成<br>消息个数",field:"last_x_s_execute_count", formatter:"html","width":100},
|
|
145
|
+
{title:"近10秒<br>运行失败<br>消息个数",field:"last_x_s_execute_count_fail", formatter:"html","width":100},
|
|
146
|
+
{title:"累计<br>运行完成<br>消息个数",field:"total_consume_count_from_start", formatter:"html","width":100},
|
|
147
|
+
{title:"累计<br>运行失败<br>消息个数",field:"total_consume_count_from_start_fail", formatter:"html","width":100},
|
|
148
|
+
|
|
149
|
+
{title: "<br><br>代码文件", field: "code_filename"},
|
|
150
|
+
// {title: "<br><br>consumer_id", field: "consumer_id"},
|
|
151
|
+
{title: "<br><br>consumer_uuid", field: "consumer_uuid"},
|
|
152
|
+
],
|
|
153
|
+
pagination: true,
|
|
154
|
+
paginationSize: 1000,
|
|
155
|
+
locale: true,
|
|
156
|
+
langs: {
|
|
157
|
+
"zh-cn": {
|
|
158
|
+
"pagination": {
|
|
159
|
+
"first": "首页",
|
|
160
|
+
"first_title": "首页",
|
|
161
|
+
"last": "末页",
|
|
162
|
+
"last_title": "末页",
|
|
163
|
+
"prev": "上一页",
|
|
164
|
+
"prev_title": "上一页",
|
|
165
|
+
"next": "下一页",
|
|
166
|
+
"next_title": "下一页",
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
<!-- $("#result-table").css("width", "150%");-->
|
|
173
|
+
|
|
174
|
+
/* result 例如 [
|
|
175
|
+
{
|
|
176
|
+
"code_filename": "d:/codes/funboost/test_frame/test_function_status_result_persist/test_persist.py",
|
|
177
|
+
"computer_ip": "10.0.133.57",
|
|
178
|
+
"computer_name": "LAPTOP-7V78BBO2",
|
|
179
|
+
"consumer_id": 1462882757512,
|
|
180
|
+
"consumer_uuid": "88f568f7-9723-48ef-9cac-0370b2333a49",
|
|
181
|
+
"consuming_function": "f2",
|
|
182
|
+
"hearbeat_datetime_str": "2025-02-25 17:28:36",
|
|
183
|
+
"hearbeat_timestamp": 1740475716.783474,
|
|
184
|
+
"process_id": 34788,
|
|
185
|
+
"queue_name": "queue_test_f02t",
|
|
186
|
+
"start_datetime_str": "2025-02-25 16:33:19",
|
|
187
|
+
"start_timestamp": 1740472399.4628778
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"code_filename": "d:/codes/funboost/test_frame/test_function_status_result_persist/test_persist.py",
|
|
191
|
+
"computer_ip": "10.0.133.57",
|
|
192
|
+
"computer_name": "LAPTOP-7V78BBO2",
|
|
193
|
+
"consumer_id": 1462882671944,
|
|
194
|
+
"consumer_uuid": "c52a8596-d632-4bac-a797-80375288f381",
|
|
195
|
+
"consuming_function": "f",
|
|
196
|
+
"hearbeat_datetime_str": "2025-02-25 17:28:36",
|
|
197
|
+
"hearbeat_timestamp": 1740475716.783336,
|
|
198
|
+
"process_id": 34788,
|
|
199
|
+
"queue_name": "queue_test_f01t",
|
|
200
|
+
"start_datetime_str": "2025-02-25 16:33:19",
|
|
201
|
+
"start_timestamp": 1740472399.4503505
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
*/
|
|
205
|
+
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
</script>
|
|
218
|
+
</body>
|
|
219
|
+
|
|
220
|
+
</html>
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
8
|
+
<title>pytho万能分布式函数调度框架</title>
|
|
9
|
+
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
|
|
10
|
+
<link href="http://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
|
11
|
+
<link rel="stylesheet"
|
|
12
|
+
href="https://cdn.bootcss.com/bootstrap-datetimepicker/4.17.47/css/bootstrap-datetimepicker.min.css">
|
|
13
|
+
<link rel="stylesheet" href="{{ url_for('static',filename='assets/css/jquery.mCustomScrollbar.min.css') }}">
|
|
14
|
+
<link rel="stylesheet" href="{{ url_for('static',filename='assets/css/custom.css') }}">
|
|
15
|
+
|
|
16
|
+
<!-- 在其他 link 标签后添加 -->
|
|
17
|
+
<link href="https://cdn.bootcdn.net/ajax/libs/select2/4.0.13/css/select2.min.css" rel="stylesheet">
|
|
18
|
+
<link href="{{ url_for('static',filename='css/content_page_style.css') }}" rel="stylesheet">
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
<script src="{{ url_for('static',filename='js/jquery-1.11.0.min.js') }}" type="text/javascript"></script>
|
|
22
|
+
<!-- <script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.11.0/jquery.min.js"></script> -->
|
|
23
|
+
<!-- 在其他 script 标签后添加 -->
|
|
24
|
+
<!-- <script src="https://cdn.bootcdn.net/ajax/libs/select2/4.0.13/js/select2.min.js"></script> -->
|
|
25
|
+
<script src="{{ url_for('static',filename='/js/select2.min.js') }}"></script>
|
|
26
|
+
<script src="http://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
<script src="{{ url_for('static',filename='js/moment-with-locales.min.js') }}"></script>
|
|
30
|
+
<script src="{{ url_for('static',filename='js/bootstrap-datetimepicker.min.js') }}"></script>
|
|
31
|
+
<!-- <script src="https://cdn.bootcss.com/bootstrap-datetimepicker/4.17.47/js/bootstrap-datetimepicker.min.js"></script> -->
|
|
32
|
+
<!-- <script type="text/javascript" src="https://cdn.bootcss.com/echarts/3.3.0/echarts.js"></script> -->
|
|
33
|
+
<script type="text/javascript" src="{{ url_for('static',filename='js/echarts.min.js') }}"></script>
|
|
34
|
+
|
|
35
|
+
<script src="{{ url_for('static',filename='assets/js/jquery.mCustomScrollbar.concat.min.js') }}"></script>
|
|
36
|
+
<script src="{{ url_for('static',filename='assets/js/custom.js') }}"></script>
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
<!-- 添加 Tabulator 样式和脚本 -->
|
|
40
|
+
<link href="https://unpkg.com/tabulator-tables@5.5.0/dist/css/tabulator.min.css" rel="stylesheet">
|
|
41
|
+
<link href="https://unpkg.com/tabulator-tables@5.5.0/dist/css/tabulator_bootstrap3.min.css" rel="stylesheet">
|
|
42
|
+
<script type="text/javascript" src="https://unpkg.com/tabulator-tables@5.5.0/dist/js/tabulator.min.js"></script>
|
|
43
|
+
|
|
44
|
+
<style>
|
|
45
|
+
|
|
46
|
+
</style>
|
|
47
|
+
</head>
|
|
48
|
+
|
|
49
|
+
<body>
|
|
50
|
+
|
|
51
|
+
<div class="container-fluid" style="margin-top: 5px;">
|
|
52
|
+
<div style="margin-top: 5px;">
|
|
53
|
+
<form class="form-inline" role="form" style="">
|
|
54
|
+
<div class="form-group ">
|
|
55
|
+
<label for="col_name_search">队列名字:</label>
|
|
56
|
+
<select class="form-control" id="col_name_search">
|
|
57
|
+
<option value="">请选择队列名字...</option>
|
|
58
|
+
</select>
|
|
59
|
+
</div>
|
|
60
|
+
<button type="button" class="btn btn-default marginLeft20" onclick="query()">查询</button>
|
|
61
|
+
</form>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<div id="result-table" style="margin-top: 20px;"></div>
|
|
65
|
+
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
<script>
|
|
74
|
+
|
|
75
|
+
// 在现有的变量声明后添加
|
|
76
|
+
var allQueues = []; // 存储所有队列数据
|
|
77
|
+
var currentColName;
|
|
78
|
+
|
|
79
|
+
// 页面加载完成后立即获取所有队列
|
|
80
|
+
$(document).ready(function () {
|
|
81
|
+
$.ajax({
|
|
82
|
+
url: "{{ url_for('hearbeat_info_partion_by_queue_name')}}",
|
|
83
|
+
data: { col_name_search: '' },
|
|
84
|
+
async: true,
|
|
85
|
+
success: function (result) {
|
|
86
|
+
allQueues = result;
|
|
87
|
+
var html = '<option value="">请选择队列名字...</option>';
|
|
88
|
+
for (var item of result) {
|
|
89
|
+
html += '<option value="' + item.collection_name + '">' +
|
|
90
|
+
item.collection_name + ' (' + item.count + ')</option>';
|
|
91
|
+
}
|
|
92
|
+
$("#col_name_search").html(html);
|
|
93
|
+
|
|
94
|
+
// 初始化选择框的搜索功能
|
|
95
|
+
$("#col_name_search").select2({
|
|
96
|
+
placeholder: "请输入队列名称搜索...",
|
|
97
|
+
allowClear: true,
|
|
98
|
+
width: '300px'
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// 监听选择变化
|
|
102
|
+
$("#col_name_search").on('change', function () {
|
|
103
|
+
var selectedQueue = $(this).val();
|
|
104
|
+
console.log("Selected queue:", selectedQueue);
|
|
105
|
+
currentColName = selectedQueue;
|
|
106
|
+
// if(selectedQueue) {
|
|
107
|
+
// queryResult(selectedQueue, 0, true);
|
|
108
|
+
// }
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
$(document).ready(function (){
|
|
115
|
+
query()
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
function query() {
|
|
119
|
+
$.ajax({
|
|
120
|
+
url: "{{ url_for('hearbeat_info_by_queue_name')}}",
|
|
121
|
+
data: { queue_name: currentColName },
|
|
122
|
+
async: true,
|
|
123
|
+
success: function (result) {
|
|
124
|
+
console.info(result);
|
|
125
|
+
|
|
126
|
+
// 创建表格
|
|
127
|
+
var table = new Tabulator("#result-table", {
|
|
128
|
+
theme: "bootstrap3",
|
|
129
|
+
data: result,
|
|
130
|
+
|
|
131
|
+
// layout: "fitColumns",
|
|
132
|
+
layout: "fitDataTable", // 改为 fitDataTable
|
|
133
|
+
responsiveLayout: false, // 禁用响应式布局
|
|
134
|
+
columns: [
|
|
135
|
+
{title: "<br><br>队列名称", field: "queue_name","width":200},
|
|
136
|
+
{title: "<br><br>消费函数", field: "consuming_function"},
|
|
137
|
+
{title: "<br><br>主机名", field: "computer_name"},
|
|
138
|
+
{title: "<br><br>IP地址", field: "computer_ip"},
|
|
139
|
+
{title: "<br><br>进程ID", field: "process_id"},
|
|
140
|
+
{title: "<br><br>启动时间", field: "start_datetime_str","width":200},
|
|
141
|
+
{title: "<br><br>最近心跳时间", field: "hearbeat_datetime_str","width":200},
|
|
142
|
+
|
|
143
|
+
{title:"近10秒<br>运行完成<br>消息个数",field:"last_x_s_execute_count", formatter:"html","width":100},
|
|
144
|
+
{title:"近10秒<br>运行失败<br>消息个数",field:"last_x_s_execute_count_fail", formatter:"html","width":100},
|
|
145
|
+
{title:"累计<br>运行完成<br>消息个数",field:"total_consume_count_from_start", formatter:"html","width":100},
|
|
146
|
+
{title:"累计<br>运行失败<br>消息个数",field:"total_consume_count_from_start_fail", formatter:"html","width":100},
|
|
147
|
+
{title: "<br><br>代码文件", field: "code_filename"},
|
|
148
|
+
// {title: "<br><br>consumer_id", field: "consumer_id"},
|
|
149
|
+
{title: "<br><br>consumer_uuid", field: "consumer_uuid"},
|
|
150
|
+
],
|
|
151
|
+
pagination: true,
|
|
152
|
+
paginationSize: 1000,
|
|
153
|
+
locale: true,
|
|
154
|
+
langs: {
|
|
155
|
+
"zh-cn": {
|
|
156
|
+
"pagination": {
|
|
157
|
+
"first": "首页",
|
|
158
|
+
"first_title": "首页",
|
|
159
|
+
"last": "末页",
|
|
160
|
+
"last_title": "末页",
|
|
161
|
+
"prev": "上一页",
|
|
162
|
+
"prev_title": "上一页",
|
|
163
|
+
"next": "下一页",
|
|
164
|
+
"next_title": "下一页",
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
/* result 例如 [
|
|
171
|
+
{
|
|
172
|
+
"code_filename": "d:/codes/funboost/test_frame/test_function_status_result_persist/test_persist.py",
|
|
173
|
+
"computer_ip": "10.0.133.57",
|
|
174
|
+
"computer_name": "LAPTOP-7V78BBO2",
|
|
175
|
+
"consumer_id": 1462882757512,
|
|
176
|
+
"consumer_uuid": "88f568f7-9723-48ef-9cac-0370b2333a49",
|
|
177
|
+
"consuming_function": "f2",
|
|
178
|
+
"hearbeat_datetime_str": "2025-02-25 17:28:36",
|
|
179
|
+
"hearbeat_timestamp": 1740475716.783474,
|
|
180
|
+
"process_id": 34788,
|
|
181
|
+
"queue_name": "queue_test_f02t",
|
|
182
|
+
"start_datetime_str": "2025-02-25 16:33:19",
|
|
183
|
+
"start_timestamp": 1740472399.4628778
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"code_filename": "d:/codes/funboost/test_frame/test_function_status_result_persist/test_persist.py",
|
|
187
|
+
"computer_ip": "10.0.133.57",
|
|
188
|
+
"computer_name": "LAPTOP-7V78BBO2",
|
|
189
|
+
"consumer_id": 1462882671944,
|
|
190
|
+
"consumer_uuid": "c52a8596-d632-4bac-a797-80375288f381",
|
|
191
|
+
"consuming_function": "f",
|
|
192
|
+
"hearbeat_datetime_str": "2025-02-25 17:28:36",
|
|
193
|
+
"hearbeat_timestamp": 1740475716.783336,
|
|
194
|
+
"process_id": 34788,
|
|
195
|
+
"queue_name": "queue_test_f01t",
|
|
196
|
+
"start_datetime_str": "2025-02-25 16:33:19",
|
|
197
|
+
"start_timestamp": 1740472399.4503505
|
|
198
|
+
}
|
|
199
|
+
]
|
|
200
|
+
*/
|
|
201
|
+
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
</script>
|
|
214
|
+
</body>
|
|
215
|
+
|
|
216
|
+
</html>
|
funboost/timing_job/__init__.py
CHANGED
|
@@ -1,221 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
"""
|
|
4
|
-
import atexit
|
|
1
|
+
from funboost.timing_job.timing_job_base import (FsdfBackgroundScheduler ,
|
|
2
|
+
funboost_aps_scheduler ,fsdf_background_scheduler,timing_publish_deco,FunboostBackgroundScheduler,push_fun_params_to_broker )
|
|
5
3
|
|
|
6
|
-
import time
|
|
7
|
-
from apscheduler.executors.pool import BasePoolExecutor
|
|
8
4
|
|
|
9
|
-
from typing import Union
|
|
10
|
-
import threading
|
|
11
5
|
|
|
12
|
-
from
|
|
13
|
-
# noinspection PyProtectedMember
|
|
14
|
-
from apscheduler.schedulers.base import STATE_STOPPED, STATE_RUNNING
|
|
15
|
-
from apscheduler.util import undefined
|
|
16
|
-
from threading import TIMEOUT_MAX
|
|
17
|
-
import deprecated
|
|
18
|
-
from funboost.utils.redis_manager import RedisMixin
|
|
19
|
-
|
|
20
|
-
from funboost.funboost_config_deafult import FunboostCommonConfig
|
|
21
|
-
|
|
22
|
-
from funboost.consumers.base_consumer import AbstractConsumer
|
|
23
|
-
from funboost.core.booster import BoostersManager, Booster
|
|
24
|
-
|
|
25
|
-
from funboost import BoosterParams
|
|
26
|
-
from funboost.concurrent_pool.custom_threadpool_executor import ThreadPoolExecutorShrinkAble
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
@deprecated.deprecated(reason='以后不要再使用这种方式,对于job_store为数据库时候需要序列化不好。使用内存和数据库都兼容的添加任务方式: add_push_job')
|
|
30
|
-
def timing_publish_deco(consuming_func_decorated_or_consumer: Union[callable, AbstractConsumer]):
|
|
31
|
-
def _deco(*args, **kwargs):
|
|
32
|
-
if getattr(consuming_func_decorated_or_consumer, 'is_decorated_as_consume_function', False) is True:
|
|
33
|
-
consuming_func_decorated_or_consumer.push(*args, **kwargs)
|
|
34
|
-
elif isinstance(consuming_func_decorated_or_consumer, AbstractConsumer):
|
|
35
|
-
consuming_func_decorated_or_consumer.publisher_of_same_queue.push(*args, **kwargs)
|
|
36
|
-
else:
|
|
37
|
-
raise TypeError('consuming_func_decorated_or_consumer 必须是被 boost 装饰的函数或者consumer类型')
|
|
38
|
-
|
|
39
|
-
return _deco
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def push_fun_params_to_broker(queue_name: str, *args, runonce_uuid=None, **kwargs):
|
|
43
|
-
"""
|
|
44
|
-
queue_name 队列名字
|
|
45
|
-
*args **kwargs 是消费函数的入参
|
|
46
|
-
发布消息中可以包括,runonce_uuid这个入参,确保分布式多个脚本都启动了定时器,导致每个定时器重复发布到消息队列,值你自己写 str(uuid.uuid4())
|
|
47
|
-
# 不需要传递 runonce_uuid 了,已经用专门的 FunboostBackgroundSchedulerProcessJobsWithinRedisLock 解决了。
|
|
48
|
-
"""
|
|
49
|
-
if runonce_uuid: # 不需要传递 runonce_uuid 了,已经用专门的 FunboostBackgroundSchedulerProcessJobsWithinRedisLock 解决了 process_jobs的问题。
|
|
50
|
-
key = 'apscheduler.redisjobstore_runonce2'
|
|
51
|
-
if RedisMixin().redis_db_frame.sadd(key, runonce_uuid):
|
|
52
|
-
BoostersManager.get_or_create_booster_by_queue_name(queue_name).push(*args, **kwargs)
|
|
53
|
-
else:
|
|
54
|
-
BoostersManager.get_or_create_booster_by_queue_name(queue_name).push(*args, **kwargs)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
class ThreadPoolExecutorForAps(BasePoolExecutor):
|
|
58
|
-
"""
|
|
59
|
-
An executor that runs jobs in a concurrent.futures thread pool.
|
|
60
|
-
|
|
61
|
-
Plugin alias: ``threadpool``
|
|
62
|
-
|
|
63
|
-
:param max_workers: the maximum number of spawned threads.
|
|
64
|
-
:param pool_kwargs: dict of keyword arguments to pass to the underlying
|
|
65
|
-
ThreadPoolExecutor constructor
|
|
66
|
-
"""
|
|
67
|
-
|
|
68
|
-
def __init__(self, max_workers=10, pool_kwargs=None):
|
|
69
|
-
pool = ThreadPoolExecutorShrinkAble(int(max_workers), )
|
|
70
|
-
super().__init__(pool)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
class FunboostBackgroundScheduler(BackgroundScheduler):
|
|
74
|
-
"""
|
|
75
|
-
自定义的, 继承了官方BackgroundScheduler,
|
|
76
|
-
通过重写 _main_loop ,使得动态修改增加删除定时任务配置更好。
|
|
77
|
-
"""
|
|
78
|
-
|
|
79
|
-
_last_wait_seconds = None
|
|
80
|
-
_last_has_task = False
|
|
81
|
-
|
|
82
|
-
@deprecated.deprecated(reason='以后不要再使用这种方式,对于job_store为数据库时候需要序列化不好。使用内存和数据库都兼容的添加任务方式: add_push_job')
|
|
83
|
-
def add_timing_publish_job(self, func, trigger=None, args=None, kwargs=None, id=None, name=None,
|
|
84
|
-
misfire_grace_time=undefined, coalesce=undefined, max_instances=undefined,
|
|
85
|
-
next_run_time=undefined, jobstore='default', executor='default',
|
|
86
|
-
replace_existing=False, **trigger_args):
|
|
87
|
-
return self.add_job(timing_publish_deco(func), trigger, args, kwargs, id, name,
|
|
88
|
-
misfire_grace_time, coalesce, max_instances,
|
|
89
|
-
next_run_time, jobstore, executor,
|
|
90
|
-
replace_existing, **trigger_args)
|
|
91
|
-
|
|
92
|
-
def add_push_job(self, func: Booster, trigger=None, args=None, kwargs=None, runonce_uuid=None,
|
|
93
|
-
id=None, name=None,
|
|
94
|
-
misfire_grace_time=undefined, coalesce=undefined, max_instances=undefined,
|
|
95
|
-
next_run_time=undefined, jobstore='default', executor='default',
|
|
96
|
-
replace_existing=False, **trigger_args, ):
|
|
97
|
-
"""
|
|
98
|
-
:param func: 被@boost装饰器装饰的函数
|
|
99
|
-
:param trigger:
|
|
100
|
-
:param args:
|
|
101
|
-
:param kwargs:
|
|
102
|
-
:param id:
|
|
103
|
-
:param name:
|
|
104
|
-
:param misfire_grace_time:
|
|
105
|
-
:param coalesce:
|
|
106
|
-
:param max_instances:
|
|
107
|
-
:param next_run_time:
|
|
108
|
-
:param jobstore:
|
|
109
|
-
:param executor:
|
|
110
|
-
:param replace_existing:
|
|
111
|
-
:param trigger_args:
|
|
112
|
-
:return:
|
|
113
|
-
"""
|
|
114
|
-
# args = args or {}
|
|
115
|
-
# kwargs['queue_name'] = func.queue_name
|
|
116
|
-
|
|
117
|
-
"""
|
|
118
|
-
用户如果不使用funboost的 FunboostBackgroundScheduler 类型对象,而是使用原生的apscheduler类型对象,可以scheduler.add_job(push_fun_params_to_broker,args=(,),kwargs={})
|
|
119
|
-
push_fun_params_to_broker函数入参是消费函数队列的 queue_name 加上 原消费函数的入参
|
|
120
|
-
"""
|
|
121
|
-
if args is None:
|
|
122
|
-
args = tuple()
|
|
123
|
-
args_list = list(args)
|
|
124
|
-
args_list.insert(0, func.queue_name)
|
|
125
|
-
args = tuple(args_list)
|
|
126
|
-
kwargs = kwargs or {}
|
|
127
|
-
kwargs['runonce_uuid'] = runonce_uuid # 忽略,用户不需要传递runonce_uuid入参。
|
|
128
|
-
return self.add_job(push_fun_params_to_broker, trigger, args, kwargs, id, name,
|
|
129
|
-
misfire_grace_time, coalesce, max_instances,
|
|
130
|
-
next_run_time, jobstore, executor,
|
|
131
|
-
replace_existing, **trigger_args, )
|
|
132
|
-
|
|
133
|
-
def start(self, paused=False, block_exit=True):
|
|
134
|
-
# def _block_exit():
|
|
135
|
-
# while True:
|
|
136
|
-
# time.sleep(3600)
|
|
137
|
-
#
|
|
138
|
-
# threading.Thread(target=_block_exit,).start() # 既不希望用BlockingScheduler阻塞主进程也不希望定时退出。
|
|
139
|
-
# self._daemon = False
|
|
140
|
-
def _when_exit():
|
|
141
|
-
while 1:
|
|
142
|
-
# print('阻止退出')
|
|
143
|
-
time.sleep(100)
|
|
144
|
-
|
|
145
|
-
if block_exit:
|
|
146
|
-
atexit.register(_when_exit)
|
|
147
|
-
super().start(paused=paused, )
|
|
148
|
-
# _block_exit() # python3.9 判断守护线程结束必须主线程在运行。你自己在你的运行代碼的最末尾加上 while 1: time.sleep(100) ,来阻止主线程退出。
|
|
149
|
-
|
|
150
|
-
def _main_loop00000(self):
|
|
151
|
-
"""
|
|
152
|
-
原来的代码是这,动态添加任务不友好。
|
|
153
|
-
:return:
|
|
154
|
-
"""
|
|
155
|
-
wait_seconds = threading.TIMEOUT_MAX
|
|
156
|
-
while self.state != STATE_STOPPED:
|
|
157
|
-
print(6666, self._event.is_set(), wait_seconds)
|
|
158
|
-
self._event.wait(wait_seconds)
|
|
159
|
-
print(7777, self._event.is_set(), wait_seconds)
|
|
160
|
-
self._event.clear()
|
|
161
|
-
wait_seconds = self._process_jobs()
|
|
162
|
-
|
|
163
|
-
def _main_loop(self):
|
|
164
|
-
"""原来的_main_loop 删除所有任务后wait_seconds 会变成None,无限等待。
|
|
165
|
-
或者下一个需要运行的任务的wait_seconds是3600秒后,此时新加了一个动态任务需要3600秒后,
|
|
166
|
-
现在最多只需要1秒就能扫描到动态新增的定时任务了。
|
|
167
|
-
"""
|
|
168
|
-
MAX_WAIT_SECONDS_FOR_NEX_PROCESS_JOBS = 0.5
|
|
169
|
-
wait_seconds = None
|
|
170
|
-
while self.state != STATE_STOPPED:
|
|
171
|
-
if wait_seconds is None:
|
|
172
|
-
wait_seconds = MAX_WAIT_SECONDS_FOR_NEX_PROCESS_JOBS
|
|
173
|
-
self._last_wait_seconds = min(wait_seconds, MAX_WAIT_SECONDS_FOR_NEX_PROCESS_JOBS)
|
|
174
|
-
if wait_seconds in (None, TIMEOUT_MAX):
|
|
175
|
-
self._last_has_task = False
|
|
176
|
-
else:
|
|
177
|
-
self._last_has_task = True
|
|
178
|
-
time.sleep(self._last_wait_seconds) # 这个要取最小值,不然例如定时间隔0.1秒运行,不取最小值,不会每隔0.1秒运行。
|
|
179
|
-
wait_seconds = self._process_jobs()
|
|
180
|
-
|
|
181
|
-
def _create_default_executor(self):
|
|
182
|
-
return ThreadPoolExecutorForAps() # 必须是apscheduler pool的子类
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
FsdfBackgroundScheduler = FunboostBackgroundScheduler # 兼容一下名字,fsdf是 function-scheduling-distributed-framework 老框架名字的缩写
|
|
186
|
-
# funboost_aps_scheduler定时配置基于内存的,不可以跨机器远程动态添加/修改/删除定时任务配置。如果需要动态增删改查定时任务,可以使用funboost_background_scheduler_redis_store
|
|
187
|
-
|
|
188
|
-
funboost_aps_scheduler = FunboostBackgroundScheduler(timezone=FunboostCommonConfig.TIMEZONE, daemon=False, )
|
|
189
|
-
fsdf_background_scheduler = funboost_aps_scheduler # 兼容一下老名字。
|
|
190
|
-
|
|
191
|
-
if __name__ == '__main__':
|
|
192
|
-
# 定时运行消费演示
|
|
193
|
-
import datetime
|
|
194
|
-
from funboost import boost, BrokerEnum, fsdf_background_scheduler, timing_publish_deco, run_forever
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
@Booster(boost_params=BoosterParams(queue_name='queue_test_666', broker_kind=BrokerEnum.LOCAL_PYTHON_QUEUE))
|
|
198
|
-
def consume_func(x, y):
|
|
199
|
-
print(f'{x} + {y} = {x + y}')
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
print(consume_func, type(consume_func))
|
|
203
|
-
|
|
204
|
-
# 定时每隔3秒执行一次。
|
|
205
|
-
funboost_aps_scheduler.add_push_job(consume_func,
|
|
206
|
-
'interval', id='3_second_job', seconds=3, kwargs={"x": 5, "y": 6})
|
|
207
|
-
|
|
208
|
-
# 定时,只执行一次
|
|
209
|
-
funboost_aps_scheduler.add_push_job(consume_func,
|
|
210
|
-
'date', run_date=datetime.datetime(2020, 7, 24, 13, 53, 6), args=(5, 6,))
|
|
211
|
-
|
|
212
|
-
# 定时,每天的11点32分20秒都执行一次。
|
|
213
|
-
funboost_aps_scheduler.add_push_job(consume_func,
|
|
214
|
-
'cron', day_of_week='*', hour=18, minute=22, second=20, args=(5, 6,))
|
|
215
|
-
|
|
216
|
-
# 启动定时
|
|
217
|
-
funboost_aps_scheduler.start()
|
|
218
|
-
|
|
219
|
-
# 启动消费
|
|
220
|
-
consume_func.consume()
|
|
221
|
-
run_forever()
|
|
6
|
+
from funboost.timing_job.timing_push import ApsJobAdder
|