beanqueue 0.2.0__tar.gz → 0.2.2__tar.gz
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.
- {beanqueue-0.2.0 → beanqueue-0.2.2}/PKG-INFO +2 -2
- {beanqueue-0.2.0 → beanqueue-0.2.2}/README.md +1 -1
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/app.py +93 -1
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/config.py +12 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/pyproject.toml +1 -1
- {beanqueue-0.2.0 → beanqueue-0.2.2}/LICENSE +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/__init__.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/cmds/__init__.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/cmds/create_tables.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/cmds/process.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/cmds/submit.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/cmds/utils.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/constants.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/db/__init__.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/db/base.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/db/session.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/events.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/models/__init__.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/models/helpers.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/models/task.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/models/worker.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/processors/__init__.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/processors/processor.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/processors/registry.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/services/__init__.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/services/dispatch.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/services/worker.py +0 -0
- {beanqueue-0.2.0 → beanqueue-0.2.2}/bq/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: beanqueue
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: BeanQueue or BQ for short, PostgreSQL SKIP LOCK based worker queue library
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Fang-Pen Lin
|
|
@@ -151,7 +151,7 @@ config = bq.Config(
|
|
|
151
151
|
app = bq.BeanQueue(config=config)
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
-
Then you can pass `--app` argument pointing to the app object to the process command like this:
|
|
154
|
+
Then you can pass `--app` argument (or `-a` for short) pointing to the app object to the process command like this:
|
|
155
155
|
|
|
156
156
|
```bash
|
|
157
157
|
python -m bq.cmds.process -a my_pkgs.bq.app images
|
|
@@ -131,7 +131,7 @@ config = bq.Config(
|
|
|
131
131
|
app = bq.BeanQueue(config=config)
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
-
Then you can pass `--app` argument pointing to the app object to the process command like this:
|
|
134
|
+
Then you can pass `--app` argument (or `-a` for short) pointing to the app object to the process command like this:
|
|
135
135
|
|
|
136
136
|
```bash
|
|
137
137
|
python -m bq.cmds.process -a my_pkgs.bq.app images
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import functools
|
|
2
2
|
import importlib
|
|
3
|
+
import json
|
|
3
4
|
import logging
|
|
4
5
|
import platform
|
|
5
6
|
import sys
|
|
6
7
|
import threading
|
|
7
8
|
import time
|
|
8
9
|
import typing
|
|
10
|
+
from wsgiref.simple_server import make_server
|
|
11
|
+
from wsgiref.simple_server import WSGIRequestHandler
|
|
9
12
|
|
|
10
13
|
import venusian
|
|
11
14
|
from sqlalchemy import func
|
|
@@ -29,6 +32,21 @@ from .utils import load_module_var
|
|
|
29
32
|
logger = logging.getLogger(__name__)
|
|
30
33
|
|
|
31
34
|
|
|
35
|
+
class WSGIRequestHandlerWithLogger(WSGIRequestHandler):
|
|
36
|
+
logger = logging.getLogger("metrics_server")
|
|
37
|
+
|
|
38
|
+
def log_message(self, format, *args):
|
|
39
|
+
message = format % args
|
|
40
|
+
self.logger.info(
|
|
41
|
+
"%s - - [%s] %s\n"
|
|
42
|
+
% (
|
|
43
|
+
self.address_string(),
|
|
44
|
+
self.log_date_time_string(),
|
|
45
|
+
message.translate(self._control_char_table),
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
32
50
|
class BeanQueue:
|
|
33
51
|
def __init__(
|
|
34
52
|
self,
|
|
@@ -150,7 +168,9 @@ class BeanQueue:
|
|
|
150
168
|
# is set too short. It could also be the administrator update the worker state to something else than
|
|
151
169
|
# RUNNING. Regardless the reason, let's stop processing.
|
|
152
170
|
logger.warning(
|
|
153
|
-
"Current worker %s state is %s instead of running, quit processing"
|
|
171
|
+
"Current worker %s state is %s instead of running, quit processing",
|
|
172
|
+
current_worker.id,
|
|
173
|
+
current_worker.state,
|
|
154
174
|
)
|
|
155
175
|
sys.exit(0)
|
|
156
176
|
|
|
@@ -159,6 +179,64 @@ class BeanQueue:
|
|
|
159
179
|
db.add(current_worker)
|
|
160
180
|
db.commit()
|
|
161
181
|
|
|
182
|
+
def _serve_http_request(
|
|
183
|
+
self, worker_id: typing.Any, environ: dict, start_response: typing.Callable
|
|
184
|
+
) -> list[bytes]:
|
|
185
|
+
path = environ["PATH_INFO"]
|
|
186
|
+
if path == "/healthz":
|
|
187
|
+
db = self.make_session()
|
|
188
|
+
worker_service = self._make_worker_service(db)
|
|
189
|
+
worker = worker_service.get_worker(worker_id)
|
|
190
|
+
if worker is not None and worker.state == models.WorkerState.RUNNING:
|
|
191
|
+
start_response(
|
|
192
|
+
"200 OK",
|
|
193
|
+
[
|
|
194
|
+
("Content-Type", "application/json"),
|
|
195
|
+
],
|
|
196
|
+
)
|
|
197
|
+
return [
|
|
198
|
+
json.dumps(dict(status="ok", worker_id=str(worker_id))).encode(
|
|
199
|
+
"utf8"
|
|
200
|
+
)
|
|
201
|
+
]
|
|
202
|
+
else:
|
|
203
|
+
logger.warning("Bad worker %s state %s", worker_id, worker.state)
|
|
204
|
+
start_response(
|
|
205
|
+
"500 Internal Server Error",
|
|
206
|
+
[
|
|
207
|
+
("Content-Type", "application/json"),
|
|
208
|
+
],
|
|
209
|
+
)
|
|
210
|
+
return [
|
|
211
|
+
json.dumps(
|
|
212
|
+
dict(
|
|
213
|
+
status="internal error",
|
|
214
|
+
worker_id=str(worker_id),
|
|
215
|
+
state=str(worker.state),
|
|
216
|
+
)
|
|
217
|
+
).encode("utf8")
|
|
218
|
+
]
|
|
219
|
+
# TODO: add other metrics endpoints
|
|
220
|
+
start_response(
|
|
221
|
+
"404 NOT FOUND",
|
|
222
|
+
[
|
|
223
|
+
("Content-Type", "application/json"),
|
|
224
|
+
],
|
|
225
|
+
)
|
|
226
|
+
return [json.dumps(dict(status="not found")).encode("utf8")]
|
|
227
|
+
|
|
228
|
+
def run_metrics_http_server(self, worker_id: typing.Any):
|
|
229
|
+
host = self.config.METRICS_HTTP_SERVER_INTERFACE
|
|
230
|
+
port = self.config.METRICS_HTTP_SERVER_PORT
|
|
231
|
+
with make_server(
|
|
232
|
+
host,
|
|
233
|
+
port,
|
|
234
|
+
functools.partial(self._serve_http_request, worker_id),
|
|
235
|
+
handler_class=WSGIRequestHandlerWithLogger,
|
|
236
|
+
) as httpd:
|
|
237
|
+
logger.info("Run metrics HTTP server on %s:%s", host, port)
|
|
238
|
+
httpd.serve_forever()
|
|
239
|
+
|
|
162
240
|
def process_tasks(
|
|
163
241
|
self,
|
|
164
242
|
channels: tuple[str, ...],
|
|
@@ -194,6 +272,18 @@ class BeanQueue:
|
|
|
194
272
|
dispatch_service.listen(channels)
|
|
195
273
|
db.commit()
|
|
196
274
|
|
|
275
|
+
metrics_server_thread = None
|
|
276
|
+
if self.config.METRICS_HTTP_SERVER_ENABLED:
|
|
277
|
+
WSGIRequestHandlerWithLogger.logger.setLevel(
|
|
278
|
+
self.config.METRICS_HTTP_SERVER_LOG_LEVEL
|
|
279
|
+
)
|
|
280
|
+
metrics_server_thread = threading.Thread(
|
|
281
|
+
target=self.run_metrics_http_server,
|
|
282
|
+
args=(worker.id,),
|
|
283
|
+
)
|
|
284
|
+
metrics_server_thread.daemon = True
|
|
285
|
+
metrics_server_thread.start()
|
|
286
|
+
|
|
197
287
|
logger.info("Created worker %s, name=%s", worker.id, worker.name)
|
|
198
288
|
events.worker_init.send(self, worker=worker)
|
|
199
289
|
|
|
@@ -249,6 +339,8 @@ class BeanQueue:
|
|
|
249
339
|
db.rollback()
|
|
250
340
|
logger.info("Shutting down ...")
|
|
251
341
|
worker_update_thread.join(5)
|
|
342
|
+
if metrics_server_thread is not None:
|
|
343
|
+
metrics_server_thread.join(5)
|
|
252
344
|
|
|
253
345
|
worker.state = models.WorkerState.SHUTDOWN
|
|
254
346
|
db.add(worker)
|
|
@@ -30,6 +30,18 @@ class Config(BaseSettings):
|
|
|
30
30
|
# which worker model to use
|
|
31
31
|
WORKER_MODEL: str = "bq.Worker"
|
|
32
32
|
|
|
33
|
+
# Enable metrics HTTP server
|
|
34
|
+
METRICS_HTTP_SERVER_ENABLED: bool = True
|
|
35
|
+
|
|
36
|
+
# the metrics http server interface to listen
|
|
37
|
+
METRICS_HTTP_SERVER_INTERFACE: str = ""
|
|
38
|
+
|
|
39
|
+
# the metrics http server port to listen
|
|
40
|
+
METRICS_HTTP_SERVER_PORT: int = 8000
|
|
41
|
+
|
|
42
|
+
# default log level for metrics http server
|
|
43
|
+
METRICS_HTTP_SERVER_LOG_LEVEL: int = 30
|
|
44
|
+
|
|
33
45
|
POSTGRES_SERVER: str = "localhost"
|
|
34
46
|
POSTGRES_USER: str = "bq"
|
|
35
47
|
POSTGRES_PASSWORD: str = ""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|