beanqueue 0.1.2__tar.gz → 0.2.0__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.1.2 → beanqueue-0.2.0}/PKG-INFO +122 -31
- {beanqueue-0.1.2 → beanqueue-0.2.0}/README.md +120 -29
- beanqueue-0.2.0/bq/__init__.py +10 -0
- beanqueue-0.2.0/bq/app.py +260 -0
- beanqueue-0.2.0/bq/cmds/create_tables.py +26 -0
- beanqueue-0.2.0/bq/cmds/process.py +23 -0
- {beanqueue-0.1.2 → beanqueue-0.2.0}/bq/cmds/submit.py +10 -10
- beanqueue-0.2.0/bq/cmds/utils.py +14 -0
- {beanqueue-0.1.2 → beanqueue-0.2.0}/bq/config.py +9 -0
- beanqueue-0.2.0/bq/constants.py +4 -0
- beanqueue-0.2.0/bq/events.py +3 -0
- beanqueue-0.2.0/bq/models/__init__.py +8 -0
- {beanqueue-0.1.2 → beanqueue-0.2.0}/bq/models/task.py +40 -26
- {beanqueue-0.1.2 → beanqueue-0.2.0}/bq/models/worker.py +25 -13
- beanqueue-0.2.0/bq/processors/processor.py +70 -0
- beanqueue-0.2.0/bq/processors/registry.py +47 -0
- {beanqueue-0.1.2 → beanqueue-0.2.0}/bq/services/dispatch.py +14 -11
- {beanqueue-0.1.2 → beanqueue-0.2.0}/bq/services/worker.py +26 -12
- beanqueue-0.2.0/bq/utils.py +8 -0
- {beanqueue-0.1.2 → beanqueue-0.2.0}/pyproject.toml +2 -2
- beanqueue-0.1.2/bq/cmds/create_tables.py +0 -25
- beanqueue-0.1.2/bq/cmds/process.py +0 -178
- beanqueue-0.1.2/bq/container.py +0 -54
- beanqueue-0.1.2/bq/models/__init__.py +0 -4
- beanqueue-0.1.2/bq/processors/registry.py +0 -136
- beanqueue-0.1.2/bq/services/__init__.py +0 -0
- {beanqueue-0.1.2 → beanqueue-0.2.0}/LICENSE +0 -0
- {beanqueue-0.1.2/bq → beanqueue-0.2.0/bq/cmds}/__init__.py +0 -0
- {beanqueue-0.1.2/bq/cmds → beanqueue-0.2.0/bq/db}/__init__.py +0 -0
- {beanqueue-0.1.2 → beanqueue-0.2.0}/bq/db/base.py +0 -0
- {beanqueue-0.1.2 → beanqueue-0.2.0}/bq/db/session.py +0 -0
- {beanqueue-0.1.2 → beanqueue-0.2.0}/bq/models/helpers.py +0 -0
- {beanqueue-0.1.2/bq/db → beanqueue-0.2.0/bq/processors}/__init__.py +0 -0
- {beanqueue-0.1.2/bq/processors → beanqueue-0.2.0/bq/services}/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: beanqueue
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
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
|
|
@@ -10,8 +10,8 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.11
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Requires-Dist: blinker (>=1.8.2,<2.0.0)
|
|
13
14
|
Requires-Dist: click (>=8.1.7,<9.0.0)
|
|
14
|
-
Requires-Dist: dependency-injector (>=4.41.0,<5.0.0)
|
|
15
15
|
Requires-Dist: pg-activity (>=3.5.1,<4.0.0)
|
|
16
16
|
Requires-Dist: pydantic-settings (>=2.2.1,<3.0.0)
|
|
17
17
|
Requires-Dist: sqlalchemy (>=2.0.30,<3.0.0)
|
|
@@ -19,7 +19,7 @@ Requires-Dist: venusian (>=3.1.0,<4.0.0)
|
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
20
|
|
|
21
21
|
# BeanQueue [](https://dl.circleci.com/status-badge/redirect/gh/LaunchPlatform/beanhub-extract/tree/master)
|
|
22
|
-
BeanQueue, a lightweight worker queue framework based on [SQLAlchemy](https://www.sqlalchemy.org/),
|
|
22
|
+
BeanQueue, a lightweight worker queue framework based on [SQLAlchemy](https://www.sqlalchemy.org/), PostgreSQL [SKIP LOCKED queries](https://www.2ndquadrant.com/en/blog/what-is-select-skip-locked-for-in-postgresql-9-5/) and [NOTIFY](https://www.postgresql.org/docs/current/sql-notify.html) / [LISTEN](https://www.postgresql.org/docs/current/sql-listen.html) statements.
|
|
23
23
|
|
|
24
24
|
**Notice**: Still in its early stage, we built this for [BeanHub](https://beanhub.io)'s internal usage. May change rapidly. Use at your own risk for now.
|
|
25
25
|
|
|
@@ -29,7 +29,7 @@ BeanQueue, a lightweight worker queue framework based on [SQLAlchemy](https://ww
|
|
|
29
29
|
- **Easy-to-deploy**: Only rely on PostgreSQL
|
|
30
30
|
- **Easy-to-use**: Provide command line tools for processing tasks, also helpers for generating tasks models
|
|
31
31
|
- **Auto-notify**: Notify will automatically be generated and send for inserted or update tasks
|
|
32
|
-
- **Worker heartbeat and auto-reschedule**: Each worker keeps updating heartbeat, if one is dead, the others will reschedule the tasks
|
|
32
|
+
- **Worker heartbeat and auto-reschedule**: Each worker keeps updating heartbeat, if one is found dead, the others will reschedule the tasks
|
|
33
33
|
- **Customizable**: Use it as an library and build your own worker queue
|
|
34
34
|
- **Native DB operations**: Commit your tasks with other db entries altogether without worrying about data inconsistent issue
|
|
35
35
|
|
|
@@ -46,14 +46,15 @@ You can define a task processor like this
|
|
|
46
46
|
```python
|
|
47
47
|
from sqlalchemy.orm import Session
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
from
|
|
51
|
-
from .. import my_models
|
|
49
|
+
import bq
|
|
50
|
+
from .. import models
|
|
52
51
|
from .. import image_utils
|
|
53
52
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
app = bq.BeanQueue()
|
|
54
|
+
|
|
55
|
+
@app.processor(channel="images")
|
|
56
|
+
def resize_image(db: Session, task: bq.Task, width: int, height: int):
|
|
57
|
+
image = db.query(models.Image).filter(models.Image.task == task).one()
|
|
57
58
|
image_utils.resize(image, size=(width, height))
|
|
58
59
|
db.add(image)
|
|
59
60
|
# by default the `processor` decorator has `auto_complete` flag turns on,
|
|
@@ -62,22 +63,23 @@ def resize_image(db: Session, task: models.Task, width: int, height: int):
|
|
|
62
63
|
|
|
63
64
|
The `db` and `task` keyword arguments are optional.
|
|
64
65
|
If you don't need to access the task object, you can simply define the function without these two parameters.
|
|
66
|
+
We also provide an optional `savepoint` argument in case if you want to rollback database changes you made.
|
|
65
67
|
|
|
66
|
-
To submit a task, you can either use `bq.
|
|
68
|
+
To submit a task, you can either use `bq.Task` model object to construct the task object, insert into the
|
|
67
69
|
database session and commit.
|
|
68
70
|
|
|
69
71
|
```python
|
|
70
|
-
|
|
72
|
+
import bq
|
|
71
73
|
from .db import Session
|
|
72
|
-
from .. import
|
|
74
|
+
from .. import models
|
|
73
75
|
|
|
74
76
|
db = Session()
|
|
75
|
-
task =
|
|
77
|
+
task = bq.Task(
|
|
76
78
|
channel="files",
|
|
77
79
|
module="my_pkgs.files.processors",
|
|
78
80
|
name="upload_to_s3_for_backup",
|
|
79
81
|
)
|
|
80
|
-
file =
|
|
82
|
+
file = models.File(
|
|
81
83
|
task=task,
|
|
82
84
|
blob_name="...",
|
|
83
85
|
)
|
|
@@ -112,6 +114,7 @@ To run the worker, you can do this:
|
|
|
112
114
|
BQ_PROCESSOR_PACKAGES='["my_pkgs.processors"]' python -m bq.cmds.process images
|
|
113
115
|
```
|
|
114
116
|
|
|
117
|
+
The `BQ_PROCESSOR_PACKAGES` is a JSON list contains the Python packages where you define your processors (the functions you decorated with `bq.processors.registry.processor`).
|
|
115
118
|
To submit a task for testing purpose, you can do
|
|
116
119
|
|
|
117
120
|
```bash
|
|
@@ -130,29 +133,116 @@ Configurations can be modified by setting environment variables with `BQ_` prefi
|
|
|
130
133
|
For example, to set the python packages to scan for processors, you can set `BQ_PROCESSOR_PACKAGES`.
|
|
131
134
|
To change the PostgreSQL database to connect to, you can set `BQ_DATABASE_URL`.
|
|
132
135
|
The complete definition of configurations can be found at the [bq/config.py](bq/config.py) module.
|
|
133
|
-
For now, the configurations only affect command line tools.
|
|
134
136
|
|
|
135
|
-
If you want to configure BeanQueue programmatically
|
|
137
|
+
If you want to configure BeanQueue programmatically, you can pass in `Config` object to the `bq.BeanQueue` object when creating.
|
|
136
138
|
For example:
|
|
137
139
|
|
|
138
140
|
```python
|
|
139
|
-
import bq
|
|
140
|
-
from
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
container
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
141
|
+
import bq
|
|
142
|
+
from .my_config import config
|
|
143
|
+
|
|
144
|
+
container = bq.Container()
|
|
145
|
+
container.wire(packages=[bq])
|
|
146
|
+
config = bq.Config(
|
|
147
|
+
PROCESSOR_PACKAGES=["my_pkgs.processors"],
|
|
148
|
+
DATABASE_URL=str(config.DATABASE_URL),
|
|
149
|
+
BATCH_SIZE=10,
|
|
150
|
+
)
|
|
151
|
+
app = bq.BeanQueue(config=config)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Then you can pass `--app` argument pointing to the app object to the process command like this:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
python -m bq.cmds.process -a my_pkgs.bq.app images
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Or if you prefer to define your own process command, you can also call `process_tasks` of the `BeanQueue` object directly like this:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
app.process_tasks(channels=("images",))
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Define your own tables
|
|
167
|
+
|
|
168
|
+
BeanQueue is designed to be as customizable as much as possible.
|
|
169
|
+
Of course, you can define your own SQLAlchemy model instead of using the ones we provided.
|
|
170
|
+
|
|
171
|
+
To make defining your own `Task` model or `Worker` model much easier, you can use our mixin classes:
|
|
172
|
+
|
|
173
|
+
- `bq.TaskModelMixin`: provides task model columns
|
|
174
|
+
- `bq.TaskModelRefWorkerMixin`: provides foreign key column and relationship to `bq.Worker`
|
|
175
|
+
- `bq.WorkerModelMixin`: provides worker model columns
|
|
176
|
+
- `bq.WorkerRefMixin`: provides relationship to `bq.Task`
|
|
177
|
+
|
|
178
|
+
Here's an example for defining your own Task model:
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
import uuid
|
|
182
|
+
|
|
183
|
+
import bq
|
|
184
|
+
from sqlalchemy import ForeignKey
|
|
185
|
+
from sqlalchemy.dialects.postgresql import UUID
|
|
186
|
+
from sqlalchemy.orm import Mapped
|
|
187
|
+
from sqlalchemy.orm import mapped_column
|
|
188
|
+
from sqlalchemy.orm import relationship
|
|
189
|
+
|
|
190
|
+
from .base_class import Base
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class Task(bq.TaskModelMixin, Base):
|
|
194
|
+
__tablename__ = "task"
|
|
195
|
+
worker_id: Mapped[uuid.UUID] = mapped_column(
|
|
196
|
+
UUID(as_uuid=True),
|
|
197
|
+
ForeignKey("worker.id", onupdate="CASCADE"),
|
|
198
|
+
nullable=True,
|
|
199
|
+
index=True,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
worker: Mapped["Worker"] = relationship(
|
|
203
|
+
"Worker", back_populates="tasks", uselist=False
|
|
150
204
|
)
|
|
151
|
-
):
|
|
152
|
-
bq.cmds.process.process_tasks(channels=("images",))
|
|
153
205
|
```
|
|
154
206
|
|
|
155
|
-
|
|
207
|
+
To make task insert and update with state changing to `PENDING` send out NOTIFY "channel" statement automatically, you can also use `bq.models.task.listen_events` helper to register our SQLAlchemy event handlers automatically like this
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
from bq.models.task import listen_events
|
|
211
|
+
listen_events(Task)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
You just see how easy it is to define your Task model. Now, here's an example for defining your own Worker model:
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
import bq
|
|
218
|
+
from sqlalchemy.orm import Mapped
|
|
219
|
+
from sqlalchemy.orm import relationship
|
|
220
|
+
|
|
221
|
+
from .base_class import Base
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class Worker(bq.WorkerModelMixin, Base):
|
|
225
|
+
__tablename__ = "worker"
|
|
226
|
+
|
|
227
|
+
tasks: Mapped[list["Task"]] = relationship(
|
|
228
|
+
"Task",
|
|
229
|
+
back_populates="worker",
|
|
230
|
+
cascade="all,delete",
|
|
231
|
+
order_by="Task.created_at",
|
|
232
|
+
)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
With the model class ready, you only need to change the `TASK_MODEL` and `WORKER_MODEL` of `Config` to the full Python module name plus the class name like this.
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
import bq
|
|
239
|
+
config = bq.Config(
|
|
240
|
+
TASK_MODEL="my_pkgs.models.Task",
|
|
241
|
+
WORKER_MODEL="my_pkgs.models.Worker",
|
|
242
|
+
# ... other configs
|
|
243
|
+
)
|
|
244
|
+
app = bq.BeanQueue(config)
|
|
245
|
+
```
|
|
156
246
|
|
|
157
247
|
## Why?
|
|
158
248
|
|
|
@@ -230,6 +320,7 @@ A modern accounting book service based on the most popular open source version c
|
|
|
230
320
|
|
|
231
321
|
- [solid_queue](https://github.com/rails/solid_queue)
|
|
232
322
|
- [postgres-tq](https://github.com/flix-tech/postgres-tq)
|
|
323
|
+
- [pq](https://github.com/malthe/pq/)
|
|
233
324
|
- [PgQueuer](https://github.com/janbjorge/PgQueuer)
|
|
234
325
|
- [hatchet](https://github.com/hatchet-dev/hatchet)
|
|
235
326
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# BeanQueue [](https://dl.circleci.com/status-badge/redirect/gh/LaunchPlatform/beanhub-extract/tree/master)
|
|
2
|
-
BeanQueue, a lightweight worker queue framework based on [SQLAlchemy](https://www.sqlalchemy.org/),
|
|
2
|
+
BeanQueue, a lightweight worker queue framework based on [SQLAlchemy](https://www.sqlalchemy.org/), PostgreSQL [SKIP LOCKED queries](https://www.2ndquadrant.com/en/blog/what-is-select-skip-locked-for-in-postgresql-9-5/) and [NOTIFY](https://www.postgresql.org/docs/current/sql-notify.html) / [LISTEN](https://www.postgresql.org/docs/current/sql-listen.html) statements.
|
|
3
3
|
|
|
4
4
|
**Notice**: Still in its early stage, we built this for [BeanHub](https://beanhub.io)'s internal usage. May change rapidly. Use at your own risk for now.
|
|
5
5
|
|
|
@@ -9,7 +9,7 @@ BeanQueue, a lightweight worker queue framework based on [SQLAlchemy](https://ww
|
|
|
9
9
|
- **Easy-to-deploy**: Only rely on PostgreSQL
|
|
10
10
|
- **Easy-to-use**: Provide command line tools for processing tasks, also helpers for generating tasks models
|
|
11
11
|
- **Auto-notify**: Notify will automatically be generated and send for inserted or update tasks
|
|
12
|
-
- **Worker heartbeat and auto-reschedule**: Each worker keeps updating heartbeat, if one is dead, the others will reschedule the tasks
|
|
12
|
+
- **Worker heartbeat and auto-reschedule**: Each worker keeps updating heartbeat, if one is found dead, the others will reschedule the tasks
|
|
13
13
|
- **Customizable**: Use it as an library and build your own worker queue
|
|
14
14
|
- **Native DB operations**: Commit your tasks with other db entries altogether without worrying about data inconsistent issue
|
|
15
15
|
|
|
@@ -26,14 +26,15 @@ You can define a task processor like this
|
|
|
26
26
|
```python
|
|
27
27
|
from sqlalchemy.orm import Session
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
from
|
|
31
|
-
from .. import my_models
|
|
29
|
+
import bq
|
|
30
|
+
from .. import models
|
|
32
31
|
from .. import image_utils
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
app = bq.BeanQueue()
|
|
34
|
+
|
|
35
|
+
@app.processor(channel="images")
|
|
36
|
+
def resize_image(db: Session, task: bq.Task, width: int, height: int):
|
|
37
|
+
image = db.query(models.Image).filter(models.Image.task == task).one()
|
|
37
38
|
image_utils.resize(image, size=(width, height))
|
|
38
39
|
db.add(image)
|
|
39
40
|
# by default the `processor` decorator has `auto_complete` flag turns on,
|
|
@@ -42,22 +43,23 @@ def resize_image(db: Session, task: models.Task, width: int, height: int):
|
|
|
42
43
|
|
|
43
44
|
The `db` and `task` keyword arguments are optional.
|
|
44
45
|
If you don't need to access the task object, you can simply define the function without these two parameters.
|
|
46
|
+
We also provide an optional `savepoint` argument in case if you want to rollback database changes you made.
|
|
45
47
|
|
|
46
|
-
To submit a task, you can either use `bq.
|
|
48
|
+
To submit a task, you can either use `bq.Task` model object to construct the task object, insert into the
|
|
47
49
|
database session and commit.
|
|
48
50
|
|
|
49
51
|
```python
|
|
50
|
-
|
|
52
|
+
import bq
|
|
51
53
|
from .db import Session
|
|
52
|
-
from .. import
|
|
54
|
+
from .. import models
|
|
53
55
|
|
|
54
56
|
db = Session()
|
|
55
|
-
task =
|
|
57
|
+
task = bq.Task(
|
|
56
58
|
channel="files",
|
|
57
59
|
module="my_pkgs.files.processors",
|
|
58
60
|
name="upload_to_s3_for_backup",
|
|
59
61
|
)
|
|
60
|
-
file =
|
|
62
|
+
file = models.File(
|
|
61
63
|
task=task,
|
|
62
64
|
blob_name="...",
|
|
63
65
|
)
|
|
@@ -92,6 +94,7 @@ To run the worker, you can do this:
|
|
|
92
94
|
BQ_PROCESSOR_PACKAGES='["my_pkgs.processors"]' python -m bq.cmds.process images
|
|
93
95
|
```
|
|
94
96
|
|
|
97
|
+
The `BQ_PROCESSOR_PACKAGES` is a JSON list contains the Python packages where you define your processors (the functions you decorated with `bq.processors.registry.processor`).
|
|
95
98
|
To submit a task for testing purpose, you can do
|
|
96
99
|
|
|
97
100
|
```bash
|
|
@@ -110,29 +113,116 @@ Configurations can be modified by setting environment variables with `BQ_` prefi
|
|
|
110
113
|
For example, to set the python packages to scan for processors, you can set `BQ_PROCESSOR_PACKAGES`.
|
|
111
114
|
To change the PostgreSQL database to connect to, you can set `BQ_DATABASE_URL`.
|
|
112
115
|
The complete definition of configurations can be found at the [bq/config.py](bq/config.py) module.
|
|
113
|
-
For now, the configurations only affect command line tools.
|
|
114
116
|
|
|
115
|
-
If you want to configure BeanQueue programmatically
|
|
117
|
+
If you want to configure BeanQueue programmatically, you can pass in `Config` object to the `bq.BeanQueue` object when creating.
|
|
116
118
|
For example:
|
|
117
119
|
|
|
118
120
|
```python
|
|
119
|
-
import bq
|
|
120
|
-
from
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
container
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
121
|
+
import bq
|
|
122
|
+
from .my_config import config
|
|
123
|
+
|
|
124
|
+
container = bq.Container()
|
|
125
|
+
container.wire(packages=[bq])
|
|
126
|
+
config = bq.Config(
|
|
127
|
+
PROCESSOR_PACKAGES=["my_pkgs.processors"],
|
|
128
|
+
DATABASE_URL=str(config.DATABASE_URL),
|
|
129
|
+
BATCH_SIZE=10,
|
|
130
|
+
)
|
|
131
|
+
app = bq.BeanQueue(config=config)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Then you can pass `--app` argument pointing to the app object to the process command like this:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
python -m bq.cmds.process -a my_pkgs.bq.app images
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Or if you prefer to define your own process command, you can also call `process_tasks` of the `BeanQueue` object directly like this:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
app.process_tasks(channels=("images",))
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Define your own tables
|
|
147
|
+
|
|
148
|
+
BeanQueue is designed to be as customizable as much as possible.
|
|
149
|
+
Of course, you can define your own SQLAlchemy model instead of using the ones we provided.
|
|
150
|
+
|
|
151
|
+
To make defining your own `Task` model or `Worker` model much easier, you can use our mixin classes:
|
|
152
|
+
|
|
153
|
+
- `bq.TaskModelMixin`: provides task model columns
|
|
154
|
+
- `bq.TaskModelRefWorkerMixin`: provides foreign key column and relationship to `bq.Worker`
|
|
155
|
+
- `bq.WorkerModelMixin`: provides worker model columns
|
|
156
|
+
- `bq.WorkerRefMixin`: provides relationship to `bq.Task`
|
|
157
|
+
|
|
158
|
+
Here's an example for defining your own Task model:
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
import uuid
|
|
162
|
+
|
|
163
|
+
import bq
|
|
164
|
+
from sqlalchemy import ForeignKey
|
|
165
|
+
from sqlalchemy.dialects.postgresql import UUID
|
|
166
|
+
from sqlalchemy.orm import Mapped
|
|
167
|
+
from sqlalchemy.orm import mapped_column
|
|
168
|
+
from sqlalchemy.orm import relationship
|
|
169
|
+
|
|
170
|
+
from .base_class import Base
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class Task(bq.TaskModelMixin, Base):
|
|
174
|
+
__tablename__ = "task"
|
|
175
|
+
worker_id: Mapped[uuid.UUID] = mapped_column(
|
|
176
|
+
UUID(as_uuid=True),
|
|
177
|
+
ForeignKey("worker.id", onupdate="CASCADE"),
|
|
178
|
+
nullable=True,
|
|
179
|
+
index=True,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
worker: Mapped["Worker"] = relationship(
|
|
183
|
+
"Worker", back_populates="tasks", uselist=False
|
|
130
184
|
)
|
|
131
|
-
):
|
|
132
|
-
bq.cmds.process.process_tasks(channels=("images",))
|
|
133
185
|
```
|
|
134
186
|
|
|
135
|
-
|
|
187
|
+
To make task insert and update with state changing to `PENDING` send out NOTIFY "channel" statement automatically, you can also use `bq.models.task.listen_events` helper to register our SQLAlchemy event handlers automatically like this
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
from bq.models.task import listen_events
|
|
191
|
+
listen_events(Task)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
You just see how easy it is to define your Task model. Now, here's an example for defining your own Worker model:
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
import bq
|
|
198
|
+
from sqlalchemy.orm import Mapped
|
|
199
|
+
from sqlalchemy.orm import relationship
|
|
200
|
+
|
|
201
|
+
from .base_class import Base
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class Worker(bq.WorkerModelMixin, Base):
|
|
205
|
+
__tablename__ = "worker"
|
|
206
|
+
|
|
207
|
+
tasks: Mapped[list["Task"]] = relationship(
|
|
208
|
+
"Task",
|
|
209
|
+
back_populates="worker",
|
|
210
|
+
cascade="all,delete",
|
|
211
|
+
order_by="Task.created_at",
|
|
212
|
+
)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
With the model class ready, you only need to change the `TASK_MODEL` and `WORKER_MODEL` of `Config` to the full Python module name plus the class name like this.
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
import bq
|
|
219
|
+
config = bq.Config(
|
|
220
|
+
TASK_MODEL="my_pkgs.models.Task",
|
|
221
|
+
WORKER_MODEL="my_pkgs.models.Worker",
|
|
222
|
+
# ... other configs
|
|
223
|
+
)
|
|
224
|
+
app = bq.BeanQueue(config)
|
|
225
|
+
```
|
|
136
226
|
|
|
137
227
|
## Why?
|
|
138
228
|
|
|
@@ -210,5 +300,6 @@ A modern accounting book service based on the most popular open source version c
|
|
|
210
300
|
|
|
211
301
|
- [solid_queue](https://github.com/rails/solid_queue)
|
|
212
302
|
- [postgres-tq](https://github.com/flix-tech/postgres-tq)
|
|
303
|
+
- [pq](https://github.com/malthe/pq/)
|
|
213
304
|
- [PgQueuer](https://github.com/janbjorge/PgQueuer)
|
|
214
305
|
- [hatchet](https://github.com/hatchet-dev/hatchet)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from .app import BeanQueue
|
|
2
|
+
from .config import Config # noqa
|
|
3
|
+
from .models import Task # noqa
|
|
4
|
+
from .models import TaskModelMixin
|
|
5
|
+
from .models import TaskModelRefWorkerMixin
|
|
6
|
+
from .models import TaskState # noqa
|
|
7
|
+
from .models import Worker # noqa
|
|
8
|
+
from .models import WorkerModelMixin # noqa
|
|
9
|
+
from .models import WorkerRefMixin # noqa
|
|
10
|
+
from .models import WorkerState # noqa
|