queuerPy 0.15.0__tar.gz → 0.17.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.
Files changed (52) hide show
  1. {queuerpy-0.15.0/queuerPy.egg-info → queuerpy-0.17.0}/PKG-INFO +82 -7
  2. {queuerpy-0.15.0 → queuerpy-0.17.0}/README.md +81 -6
  3. {queuerpy-0.15.0 → queuerpy-0.17.0}/_version.py +1 -1
  4. {queuerpy-0.15.0 → queuerpy-0.17.0}/database/db_job.py +13 -5
  5. {queuerpy-0.15.0 → queuerpy-0.17.0}/model/batch_job.py +4 -3
  6. {queuerpy-0.15.0 → queuerpy-0.17.0}/model/job.py +16 -1
  7. {queuerpy-0.15.0 → queuerpy-0.17.0}/pyproject.toml +2 -2
  8. {queuerpy-0.15.0 → queuerpy-0.17.0/queuerPy.egg-info}/PKG-INFO +82 -7
  9. {queuerpy-0.15.0 → queuerpy-0.17.0}/queuer_job.py +25 -9
  10. {queuerpy-0.15.0 → queuerpy-0.17.0}/sql/job.sql +102 -16
  11. {queuerpy-0.15.0 → queuerpy-0.17.0}/sql/worker.sql +17 -0
  12. {queuerpy-0.15.0 → queuerpy-0.17.0}/LICENSE +0 -0
  13. {queuerpy-0.15.0 → queuerpy-0.17.0}/MANIFEST.in +0 -0
  14. {queuerpy-0.15.0 → queuerpy-0.17.0}/__init__.py +0 -0
  15. {queuerpy-0.15.0 → queuerpy-0.17.0}/core/__init__.py +0 -0
  16. {queuerpy-0.15.0 → queuerpy-0.17.0}/core/broadcaster.py +0 -0
  17. {queuerpy-0.15.0 → queuerpy-0.17.0}/core/listener.py +0 -0
  18. {queuerpy-0.15.0 → queuerpy-0.17.0}/core/retryer.py +0 -0
  19. {queuerpy-0.15.0 → queuerpy-0.17.0}/core/runner.py +0 -0
  20. {queuerpy-0.15.0 → queuerpy-0.17.0}/core/scheduler.py +0 -0
  21. {queuerpy-0.15.0 → queuerpy-0.17.0}/core/ticker.py +0 -0
  22. {queuerpy-0.15.0 → queuerpy-0.17.0}/database/__init__.py +0 -0
  23. {queuerpy-0.15.0 → queuerpy-0.17.0}/database/db_listener.py +0 -0
  24. {queuerpy-0.15.0 → queuerpy-0.17.0}/database/db_master.py +0 -0
  25. {queuerpy-0.15.0 → queuerpy-0.17.0}/database/db_worker.py +0 -0
  26. {queuerpy-0.15.0 → queuerpy-0.17.0}/helper/__init__.py +0 -0
  27. {queuerpy-0.15.0 → queuerpy-0.17.0}/helper/database.py +0 -0
  28. {queuerpy-0.15.0 → queuerpy-0.17.0}/helper/error.py +0 -0
  29. {queuerpy-0.15.0 → queuerpy-0.17.0}/helper/logging.py +0 -0
  30. {queuerpy-0.15.0 → queuerpy-0.17.0}/helper/sql.py +0 -0
  31. {queuerpy-0.15.0 → queuerpy-0.17.0}/helper/task.py +0 -0
  32. {queuerpy-0.15.0 → queuerpy-0.17.0}/model/__init__.py +0 -0
  33. {queuerpy-0.15.0 → queuerpy-0.17.0}/model/connection.py +0 -0
  34. {queuerpy-0.15.0 → queuerpy-0.17.0}/model/master.py +0 -0
  35. {queuerpy-0.15.0 → queuerpy-0.17.0}/model/options.py +0 -0
  36. {queuerpy-0.15.0 → queuerpy-0.17.0}/model/options_on_error.py +0 -0
  37. {queuerpy-0.15.0 → queuerpy-0.17.0}/model/task.py +0 -0
  38. {queuerpy-0.15.0 → queuerpy-0.17.0}/model/worker.py +0 -0
  39. {queuerpy-0.15.0 → queuerpy-0.17.0}/py.typed +0 -0
  40. {queuerpy-0.15.0 → queuerpy-0.17.0}/queuer.py +0 -0
  41. {queuerpy-0.15.0 → queuerpy-0.17.0}/queuerPy.egg-info/SOURCES.txt +0 -0
  42. {queuerpy-0.15.0 → queuerpy-0.17.0}/queuerPy.egg-info/dependency_links.txt +0 -0
  43. {queuerpy-0.15.0 → queuerpy-0.17.0}/queuerPy.egg-info/requires.txt +0 -0
  44. {queuerpy-0.15.0 → queuerpy-0.17.0}/queuerPy.egg-info/top_level.txt +0 -0
  45. {queuerpy-0.15.0 → queuerpy-0.17.0}/queuer_global.py +0 -0
  46. {queuerpy-0.15.0 → queuerpy-0.17.0}/queuer_listener.py +0 -0
  47. {queuerpy-0.15.0 → queuerpy-0.17.0}/queuer_master.py +0 -0
  48. {queuerpy-0.15.0 → queuerpy-0.17.0}/queuer_next_interval.py +0 -0
  49. {queuerpy-0.15.0 → queuerpy-0.17.0}/queuer_task.py +0 -0
  50. {queuerpy-0.15.0 → queuerpy-0.17.0}/setup.cfg +0 -0
  51. {queuerpy-0.15.0 → queuerpy-0.17.0}/sql/master.sql +0 -0
  52. {queuerpy-0.15.0 → queuerpy-0.17.0}/sql/notify.sql +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: queuerPy
3
- Version: 0.15.0
3
+ Version: 0.17.0
4
4
  Summary: A Python implementation of the queuer system - a job queuing and processing system with PostgreSQL backend
5
5
  Author-email: Simon Herrmann <siherrmann@users.noreply.github.com>
6
6
  Maintainer-email: Simon Herrmann <siherrmann@users.noreply.github.com>
@@ -43,9 +43,10 @@ Dynamic: license-file
43
43
 
44
44
  # queuerPy
45
45
 
46
+ [![PyPi](https://pythonico.leapcell.app/pypi/queuerPy.svg?style=shields&data=n,v,d)](https://pypi.org/project/queuerPy/)
46
47
  [![Python](https://img.shields.io/badge/Python-3.10+-blue.svg)](https://www.python.org/)
47
- [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/siherrmann/queuer/blob/master/LICENSE)
48
48
  ![Coverage](https://raw.githubusercontent.com/siherrmann/queuerPy/refs/heads/main/coverage-badge.svg)
49
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/siherrmann/queuer/blob/master/LICENSE)
49
50
 
50
51
  Python port of the queuer package - a queueing system based on PostgreSQL.
51
52
 
@@ -97,9 +98,15 @@ def example_task():
97
98
  That's easy, right? Adding a job is just as easy:
98
99
 
99
100
  ```python
100
- # Add a job to the queue
101
+ # Add a job to the queue with positional arguments
101
102
  job = q.add_job(example_task, 5, "12")
102
103
  print(f"Job added: {job.rid}")
104
+
105
+ # Add a job with keyword arguments (kwargs)
106
+ job = q.add_job(example_task, paramKeyed1="test", debug=True)
107
+
108
+ # Add a job with both positional and keyword arguments
109
+ job = q.add_job(example_task, 5, "12", paramKeyed1="test", debug=True)
103
110
  ```
104
111
 
105
112
  In the initialisation of the queuer the existence of the necessary database tables is checked and if they don't exist they get created. The database is configured with these environment variables:
@@ -199,6 +206,72 @@ This method handles the registration of a task, making the worker able to pick u
199
206
 
200
207
  ---
201
208
 
209
+ ## add_job
210
+
211
+ The `add_job` method adds a new job to the queue for execution. Jobs are units of work that will be processed by the queuer.
212
+
213
+ ```python
214
+ def add_job(
215
+ self,
216
+ task: Union[Callable, str],
217
+ *parameters: Any,
218
+ **parameters_keyed: Any
219
+ ) -> Job
220
+
221
+ def add_job_with_options(
222
+ self,
223
+ options: Optional[Options],
224
+ task: Union[Callable, str],
225
+ *parameters: Any,
226
+ **parameters_keyed: Any
227
+ ) -> Job
228
+ ```
229
+
230
+ - `task`: A `Callable` or `str` representing the task to execute. If a callable, it must be registered with `add_task` first.
231
+ - `options`: Optional `Options` for custom error handling or scheduling behavior. Only available in `add_job_with_options()`.
232
+ - `*parameters`: Positional arguments to pass to the task function.
233
+ - `**parameters_keyed`: Keyword arguments to pass to the task function (Python-specific feature).
234
+
235
+ **Examples:**
236
+
237
+ ```python
238
+ # Job with both positional and keyword arguments
239
+ job = queuer.add_job(my_task, "arg1", paramKeyed1="test", paramKeyed2=1)
240
+
241
+ # Job with custom options (requires add_job_with_options)
242
+ options = Options(on_error=OnError(max_retries=5))
243
+ job = queuer.add_job_with_options(options, my_task, "arg1", debug=True)
244
+ ```
245
+
246
+ **Note:** Keyword arguments (`**parameters_keyed`) are stored separately in the database and enable Python functions to be called with named parameters. This is useful for optional parameters, default values, and improved code clarity. Go jobs continue to use only positional parameters.
247
+
248
+ ---
249
+
250
+ ## add_jobs
251
+
252
+ The `add_jobs` method allows efficient batch insertion of multiple jobs at once.
253
+
254
+ ```python
255
+ def add_jobs(self, batch_jobs: List[BatchJob]) -> List[UUID]
256
+ ```
257
+
258
+ - `batch_jobs`: A list of `BatchJob` instances to insert.
259
+
260
+ **Example:**
261
+
262
+ ```python
263
+ from model.batch_job import BatchJob
264
+
265
+ batch = [
266
+ BatchJob(task=my_task, parameters=[1, "a"]),
267
+ BatchJob(task=my_task, parameters=[2], parameters_keyed={"name": "b"}),
268
+ BatchJob(task=my_task, parameters_keyed={"id": 3, "name": "c"})
269
+ ]
270
+ job_rids = queuer.add_jobs(batch)
271
+ ```
272
+
273
+ ---
274
+
202
275
  ## add_next_interval_func
203
276
 
204
277
  The `add_next_interval_func` method registers a custom function that determines the next execution time for scheduled jobs. This is useful for implementing complex scheduling logic beyond simple fixed intervals.
@@ -296,19 +369,20 @@ class Schedule:
296
369
  ### Job Management
297
370
 
298
371
  ```python
299
- # Add a single job
300
- job = queuer.add_job(my_task, param1, param2)
372
+ # Add a job with both positional and keyword arguments
373
+ job = queuer.add_job(my_task, param1, param2, paramKeyed1="test", paramKeyed2=1)
301
374
 
302
375
  # Add a job with custom options
303
376
  from model.options import Options, OnError
304
377
  options = Options(on_error=OnError(max_retries=5, timeout=60.0))
305
- job = queuer.add_job_with_options(options, my_task, param1)
378
+ job = queuer.add_job_with_options(options, my_task, param1, paramKeyed1="test")
306
379
 
307
380
  # Add multiple jobs as a batch
308
381
  from model.batch_job import BatchJob
309
382
  batch = [
310
383
  BatchJob(task=my_task, parameters=[1, "a"]),
311
- BatchJob(task=my_task, parameters=[2, "b"])
384
+ BatchJob(task=my_task, parameters=[2], parameters_keyed={"name": "b"}),
385
+ BatchJob(task=my_task, parameters_keyed={"id": 3, "name": "c"})
312
386
  ]
313
387
  queuer.add_jobs(batch)
314
388
 
@@ -335,6 +409,7 @@ worker_jobs = queuer.get_jobs_by_worker_rid(worker.rid)
335
409
 
336
410
  # ⭐ Features
337
411
 
412
+ - **Keyword Arguments Support**: Python functions can use both positional arguments (`*args`) and keyword arguments (`**kwargs`), while maintaining compatibility with Go jobs that use only positional parameters.
338
413
  - **Async/Await Support**: Full asyncio integration with threading fallbacks.
339
414
  - **PostgreSQL NOTIFY/LISTEN**: Real-time job notifications without polling overhead.
340
415
  - **Batch Job Processing**: Insert job batches efficiently using PostgreSQL's `COPY FROM` feature.
@@ -1,8 +1,9 @@
1
1
  # queuerPy
2
2
 
3
+ [![PyPi](https://pythonico.leapcell.app/pypi/queuerPy.svg?style=shields&data=n,v,d)](https://pypi.org/project/queuerPy/)
3
4
  [![Python](https://img.shields.io/badge/Python-3.10+-blue.svg)](https://www.python.org/)
4
- [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/siherrmann/queuer/blob/master/LICENSE)
5
5
  ![Coverage](https://raw.githubusercontent.com/siherrmann/queuerPy/refs/heads/main/coverage-badge.svg)
6
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/siherrmann/queuer/blob/master/LICENSE)
6
7
 
7
8
  Python port of the queuer package - a queueing system based on PostgreSQL.
8
9
 
@@ -54,9 +55,15 @@ def example_task():
54
55
  That's easy, right? Adding a job is just as easy:
55
56
 
56
57
  ```python
57
- # Add a job to the queue
58
+ # Add a job to the queue with positional arguments
58
59
  job = q.add_job(example_task, 5, "12")
59
60
  print(f"Job added: {job.rid}")
61
+
62
+ # Add a job with keyword arguments (kwargs)
63
+ job = q.add_job(example_task, paramKeyed1="test", debug=True)
64
+
65
+ # Add a job with both positional and keyword arguments
66
+ job = q.add_job(example_task, 5, "12", paramKeyed1="test", debug=True)
60
67
  ```
61
68
 
62
69
  In the initialisation of the queuer the existence of the necessary database tables is checked and if they don't exist they get created. The database is configured with these environment variables:
@@ -156,6 +163,72 @@ This method handles the registration of a task, making the worker able to pick u
156
163
 
157
164
  ---
158
165
 
166
+ ## add_job
167
+
168
+ The `add_job` method adds a new job to the queue for execution. Jobs are units of work that will be processed by the queuer.
169
+
170
+ ```python
171
+ def add_job(
172
+ self,
173
+ task: Union[Callable, str],
174
+ *parameters: Any,
175
+ **parameters_keyed: Any
176
+ ) -> Job
177
+
178
+ def add_job_with_options(
179
+ self,
180
+ options: Optional[Options],
181
+ task: Union[Callable, str],
182
+ *parameters: Any,
183
+ **parameters_keyed: Any
184
+ ) -> Job
185
+ ```
186
+
187
+ - `task`: A `Callable` or `str` representing the task to execute. If a callable, it must be registered with `add_task` first.
188
+ - `options`: Optional `Options` for custom error handling or scheduling behavior. Only available in `add_job_with_options()`.
189
+ - `*parameters`: Positional arguments to pass to the task function.
190
+ - `**parameters_keyed`: Keyword arguments to pass to the task function (Python-specific feature).
191
+
192
+ **Examples:**
193
+
194
+ ```python
195
+ # Job with both positional and keyword arguments
196
+ job = queuer.add_job(my_task, "arg1", paramKeyed1="test", paramKeyed2=1)
197
+
198
+ # Job with custom options (requires add_job_with_options)
199
+ options = Options(on_error=OnError(max_retries=5))
200
+ job = queuer.add_job_with_options(options, my_task, "arg1", debug=True)
201
+ ```
202
+
203
+ **Note:** Keyword arguments (`**parameters_keyed`) are stored separately in the database and enable Python functions to be called with named parameters. This is useful for optional parameters, default values, and improved code clarity. Go jobs continue to use only positional parameters.
204
+
205
+ ---
206
+
207
+ ## add_jobs
208
+
209
+ The `add_jobs` method allows efficient batch insertion of multiple jobs at once.
210
+
211
+ ```python
212
+ def add_jobs(self, batch_jobs: List[BatchJob]) -> List[UUID]
213
+ ```
214
+
215
+ - `batch_jobs`: A list of `BatchJob` instances to insert.
216
+
217
+ **Example:**
218
+
219
+ ```python
220
+ from model.batch_job import BatchJob
221
+
222
+ batch = [
223
+ BatchJob(task=my_task, parameters=[1, "a"]),
224
+ BatchJob(task=my_task, parameters=[2], parameters_keyed={"name": "b"}),
225
+ BatchJob(task=my_task, parameters_keyed={"id": 3, "name": "c"})
226
+ ]
227
+ job_rids = queuer.add_jobs(batch)
228
+ ```
229
+
230
+ ---
231
+
159
232
  ## add_next_interval_func
160
233
 
161
234
  The `add_next_interval_func` method registers a custom function that determines the next execution time for scheduled jobs. This is useful for implementing complex scheduling logic beyond simple fixed intervals.
@@ -253,19 +326,20 @@ class Schedule:
253
326
  ### Job Management
254
327
 
255
328
  ```python
256
- # Add a single job
257
- job = queuer.add_job(my_task, param1, param2)
329
+ # Add a job with both positional and keyword arguments
330
+ job = queuer.add_job(my_task, param1, param2, paramKeyed1="test", paramKeyed2=1)
258
331
 
259
332
  # Add a job with custom options
260
333
  from model.options import Options, OnError
261
334
  options = Options(on_error=OnError(max_retries=5, timeout=60.0))
262
- job = queuer.add_job_with_options(options, my_task, param1)
335
+ job = queuer.add_job_with_options(options, my_task, param1, paramKeyed1="test")
263
336
 
264
337
  # Add multiple jobs as a batch
265
338
  from model.batch_job import BatchJob
266
339
  batch = [
267
340
  BatchJob(task=my_task, parameters=[1, "a"]),
268
- BatchJob(task=my_task, parameters=[2, "b"])
341
+ BatchJob(task=my_task, parameters=[2], parameters_keyed={"name": "b"}),
342
+ BatchJob(task=my_task, parameters_keyed={"id": 3, "name": "c"})
269
343
  ]
270
344
  queuer.add_jobs(batch)
271
345
 
@@ -292,6 +366,7 @@ worker_jobs = queuer.get_jobs_by_worker_rid(worker.rid)
292
366
 
293
367
  # ⭐ Features
294
368
 
369
+ - **Keyword Arguments Support**: Python functions can use both positional arguments (`*args`) and keyword arguments (`**kwargs`), while maintaining compatibility with Go jobs that use only positional parameters.
295
370
  - **Async/Await Support**: Full asyncio integration with threading fallbacks.
296
371
  - **PostgreSQL NOTIFY/LISTEN**: Real-time job notifications without polling overhead.
297
372
  - **Batch Job Processing**: Insert job batches efficiently using PostgreSQL's `COPY FROM` feature.
@@ -1,6 +1,6 @@
1
1
  """Version information for queuerPy package."""
2
2
 
3
- __version__ = "0.15.0"
3
+ __version__ = "0.17.0"
4
4
  __version_info__ = tuple(int(part) for part in __version__.split("."))
5
5
 
6
6
  # For compatibility
@@ -95,11 +95,12 @@ class JobDBHandler:
95
95
 
96
96
  with self.db.instance.cursor(row_factory=dict_row) as cur:
97
97
  cur.execute(
98
- "SELECT * FROM insert_job(%s, %s, %s, %s, %s, %s);",
98
+ "SELECT * FROM insert_job(%s, %s, %s, %s, %s, %s, %s);",
99
99
  (
100
100
  json.dumps(job.options.to_dict()) if job.options else None,
101
101
  job.task_name,
102
102
  json.dumps(job.parameters),
103
+ json.dumps(job.parameters_keyed),
103
104
  job.status,
104
105
  job.scheduled_at,
105
106
  job.schedule_count,
@@ -144,21 +145,28 @@ class JobDBHandler:
144
145
  raise ValueError("Database connection is not established")
145
146
 
146
147
  try:
147
- batch_data: List[Tuple[str, str, str, Optional[datetime]]] = []
148
+ batch_data: List[Tuple[str, str, str, str, Optional[datetime]]] = []
148
149
  for job in jobs:
149
150
  options_json = (
150
151
  json.dumps(job.options.to_dict()) if job.options else "{}"
151
152
  )
152
153
  parameters_json = json.dumps(job.parameters)
154
+ parameters_keyed_json = json.dumps(job.parameters_keyed)
153
155
  batch_data.append(
154
- (options_json, job.task_name, parameters_json, job.scheduled_at)
156
+ (
157
+ options_json,
158
+ job.task_name,
159
+ parameters_json,
160
+ parameters_keyed_json,
161
+ job.scheduled_at,
162
+ )
155
163
  )
156
164
 
157
165
  with self.db.instance.cursor(row_factory=dict_row) as cur:
158
166
  cur.executemany(
159
167
  """
160
- INSERT INTO job (options, task_name, parameters, scheduled_at)
161
- VALUES (%s, %s, %s, %s)
168
+ INSERT INTO job (options, task_name, parameters, parameters_keyed, scheduled_at)
169
+ VALUES (%s, %s, %s, %s, %s)
162
170
  """,
163
171
  batch_data,
164
172
  )
@@ -3,8 +3,8 @@ BatchJob model for Python queuer implementation.
3
3
  Mirrors Go's model.BatchJob struct.
4
4
  """
5
5
 
6
- from typing import Any, List, Optional, Union, Callable
7
- from dataclasses import dataclass
6
+ from typing import Any, Dict, List, Optional, Union, Callable
7
+ from dataclasses import dataclass, field
8
8
 
9
9
  from .options import Options
10
10
 
@@ -16,5 +16,6 @@ class BatchJob:
16
16
  """
17
17
 
18
18
  task: Union[Callable[..., Any], str]
19
- parameters: List[Any]
19
+ parameters: List[Any] = field(default_factory=list)
20
+ parameters_keyed: Dict[str, Any] = field(default_factory=dict)
20
21
  options: Optional[Options] = None
@@ -40,7 +40,8 @@ class Job:
40
40
 
41
41
  # Job definition
42
42
  task_name: str = ""
43
- parameters: List[Any] = field(default_factory=lambda: [])
43
+ parameters: List[Any] = field(default_factory=list)
44
+ parameters_keyed: Dict[str, Any] = field(default_factory=dict)
44
45
  options: Optional[Options] = None
45
46
 
46
47
  # Job state
@@ -65,6 +66,7 @@ class Job:
65
66
  "worker_rid": str(self.worker_rid),
66
67
  "task_name": self.task_name,
67
68
  "parameters": self.parameters,
69
+ "parameters_keyed": self.parameters_keyed,
68
70
  "options": self.options.to_dict() if self.options else None,
69
71
  "status": self.status,
70
72
  "scheduled_at": (
@@ -110,6 +112,7 @@ class Job:
110
112
  job.worker_rid = UUID(data["worker_rid"])
111
113
  job.task_name = data.get("task_name", "")
112
114
  job.parameters = data.get("parameters", [])
115
+ job.parameters_keyed = data.get("parameters_keyed", {})
113
116
  if data.get("options"):
114
117
  job.options = Options.from_dict(data["options"])
115
118
  job.status = data.get("status", JobStatus.QUEUED)
@@ -173,6 +176,16 @@ class Job:
173
176
  else parameters_value
174
177
  )
175
178
 
179
+ parameters_keyed_value = row.get(
180
+ "output_parameters_keyed", row.get("parameters_keyed")
181
+ )
182
+ if parameters_keyed_value:
183
+ job.parameters_keyed = (
184
+ json.loads(parameters_keyed_value)
185
+ if isinstance(parameters_keyed_value, str)
186
+ else parameters_keyed_value
187
+ )
188
+
176
189
  results_value = row.get("output_results", row.get("results"))
177
190
  if results_value is not None:
178
191
  # JSONB columns return Python objects directly, no JSON parsing needed
@@ -194,6 +207,7 @@ def new_job(
194
207
  task: Union[Callable[..., Any], str],
195
208
  options: Optional[Options] = None,
196
209
  *parameters: Any,
210
+ **parameters_keyed: Any,
197
211
  ) -> Job:
198
212
  """
199
213
  Create a new job from a task function or task name.
@@ -237,6 +251,7 @@ def new_job(
237
251
  job: Job = Job()
238
252
  job.task_name = task_name
239
253
  job.parameters = list(parameters)
254
+ job.parameters_keyed = parameters_keyed
240
255
  job.options = options
241
256
  job.status = status
242
257
  job.scheduled_at = scheduled_at
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "queuerPy"
7
- version = "0.15.0"
7
+ version = "0.17.0"
8
8
  description = "A Python implementation of the queuer system - a job queuing and processing system with PostgreSQL backend"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -92,7 +92,7 @@ pythonVersion = "3.8"
92
92
  pythonPlatform = "All"
93
93
 
94
94
  [tool.mypy]
95
- python_version = "0.15.0"
95
+ python_version = "0.17.0"
96
96
  warn_return_any = true
97
97
  warn_unused_configs = true
98
98
  disallow_untyped_defs = true
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: queuerPy
3
- Version: 0.15.0
3
+ Version: 0.17.0
4
4
  Summary: A Python implementation of the queuer system - a job queuing and processing system with PostgreSQL backend
5
5
  Author-email: Simon Herrmann <siherrmann@users.noreply.github.com>
6
6
  Maintainer-email: Simon Herrmann <siherrmann@users.noreply.github.com>
@@ -43,9 +43,10 @@ Dynamic: license-file
43
43
 
44
44
  # queuerPy
45
45
 
46
+ [![PyPi](https://pythonico.leapcell.app/pypi/queuerPy.svg?style=shields&data=n,v,d)](https://pypi.org/project/queuerPy/)
46
47
  [![Python](https://img.shields.io/badge/Python-3.10+-blue.svg)](https://www.python.org/)
47
- [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/siherrmann/queuer/blob/master/LICENSE)
48
48
  ![Coverage](https://raw.githubusercontent.com/siherrmann/queuerPy/refs/heads/main/coverage-badge.svg)
49
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/siherrmann/queuer/blob/master/LICENSE)
49
50
 
50
51
  Python port of the queuer package - a queueing system based on PostgreSQL.
51
52
 
@@ -97,9 +98,15 @@ def example_task():
97
98
  That's easy, right? Adding a job is just as easy:
98
99
 
99
100
  ```python
100
- # Add a job to the queue
101
+ # Add a job to the queue with positional arguments
101
102
  job = q.add_job(example_task, 5, "12")
102
103
  print(f"Job added: {job.rid}")
104
+
105
+ # Add a job with keyword arguments (kwargs)
106
+ job = q.add_job(example_task, paramKeyed1="test", debug=True)
107
+
108
+ # Add a job with both positional and keyword arguments
109
+ job = q.add_job(example_task, 5, "12", paramKeyed1="test", debug=True)
103
110
  ```
104
111
 
105
112
  In the initialisation of the queuer the existence of the necessary database tables is checked and if they don't exist they get created. The database is configured with these environment variables:
@@ -199,6 +206,72 @@ This method handles the registration of a task, making the worker able to pick u
199
206
 
200
207
  ---
201
208
 
209
+ ## add_job
210
+
211
+ The `add_job` method adds a new job to the queue for execution. Jobs are units of work that will be processed by the queuer.
212
+
213
+ ```python
214
+ def add_job(
215
+ self,
216
+ task: Union[Callable, str],
217
+ *parameters: Any,
218
+ **parameters_keyed: Any
219
+ ) -> Job
220
+
221
+ def add_job_with_options(
222
+ self,
223
+ options: Optional[Options],
224
+ task: Union[Callable, str],
225
+ *parameters: Any,
226
+ **parameters_keyed: Any
227
+ ) -> Job
228
+ ```
229
+
230
+ - `task`: A `Callable` or `str` representing the task to execute. If a callable, it must be registered with `add_task` first.
231
+ - `options`: Optional `Options` for custom error handling or scheduling behavior. Only available in `add_job_with_options()`.
232
+ - `*parameters`: Positional arguments to pass to the task function.
233
+ - `**parameters_keyed`: Keyword arguments to pass to the task function (Python-specific feature).
234
+
235
+ **Examples:**
236
+
237
+ ```python
238
+ # Job with both positional and keyword arguments
239
+ job = queuer.add_job(my_task, "arg1", paramKeyed1="test", paramKeyed2=1)
240
+
241
+ # Job with custom options (requires add_job_with_options)
242
+ options = Options(on_error=OnError(max_retries=5))
243
+ job = queuer.add_job_with_options(options, my_task, "arg1", debug=True)
244
+ ```
245
+
246
+ **Note:** Keyword arguments (`**parameters_keyed`) are stored separately in the database and enable Python functions to be called with named parameters. This is useful for optional parameters, default values, and improved code clarity. Go jobs continue to use only positional parameters.
247
+
248
+ ---
249
+
250
+ ## add_jobs
251
+
252
+ The `add_jobs` method allows efficient batch insertion of multiple jobs at once.
253
+
254
+ ```python
255
+ def add_jobs(self, batch_jobs: List[BatchJob]) -> List[UUID]
256
+ ```
257
+
258
+ - `batch_jobs`: A list of `BatchJob` instances to insert.
259
+
260
+ **Example:**
261
+
262
+ ```python
263
+ from model.batch_job import BatchJob
264
+
265
+ batch = [
266
+ BatchJob(task=my_task, parameters=[1, "a"]),
267
+ BatchJob(task=my_task, parameters=[2], parameters_keyed={"name": "b"}),
268
+ BatchJob(task=my_task, parameters_keyed={"id": 3, "name": "c"})
269
+ ]
270
+ job_rids = queuer.add_jobs(batch)
271
+ ```
272
+
273
+ ---
274
+
202
275
  ## add_next_interval_func
203
276
 
204
277
  The `add_next_interval_func` method registers a custom function that determines the next execution time for scheduled jobs. This is useful for implementing complex scheduling logic beyond simple fixed intervals.
@@ -296,19 +369,20 @@ class Schedule:
296
369
  ### Job Management
297
370
 
298
371
  ```python
299
- # Add a single job
300
- job = queuer.add_job(my_task, param1, param2)
372
+ # Add a job with both positional and keyword arguments
373
+ job = queuer.add_job(my_task, param1, param2, paramKeyed1="test", paramKeyed2=1)
301
374
 
302
375
  # Add a job with custom options
303
376
  from model.options import Options, OnError
304
377
  options = Options(on_error=OnError(max_retries=5, timeout=60.0))
305
- job = queuer.add_job_with_options(options, my_task, param1)
378
+ job = queuer.add_job_with_options(options, my_task, param1, paramKeyed1="test")
306
379
 
307
380
  # Add multiple jobs as a batch
308
381
  from model.batch_job import BatchJob
309
382
  batch = [
310
383
  BatchJob(task=my_task, parameters=[1, "a"]),
311
- BatchJob(task=my_task, parameters=[2, "b"])
384
+ BatchJob(task=my_task, parameters=[2], parameters_keyed={"name": "b"}),
385
+ BatchJob(task=my_task, parameters_keyed={"id": 3, "name": "c"})
312
386
  ]
313
387
  queuer.add_jobs(batch)
314
388
 
@@ -335,6 +409,7 @@ worker_jobs = queuer.get_jobs_by_worker_rid(worker.rid)
335
409
 
336
410
  # ⭐ Features
337
411
 
412
+ - **Keyword Arguments Support**: Python functions can use both positional arguments (`*args`) and keyword arguments (`**kwargs`), while maintaining compatibility with Go jobs that use only positional parameters.
338
413
  - **Async/Await Support**: Full asyncio integration with threading fallbacks.
339
414
  - **PostgreSQL NOTIFY/LISTEN**: Real-time job notifications without polling overhead.
340
415
  - **Batch Job Processing**: Insert job batches efficiently using PostgreSQL's `COPY FROM` feature.
@@ -34,17 +34,23 @@ class QueuerJobMixin(QueuerGlobalMixin):
34
34
  def __init__(self):
35
35
  super().__init__()
36
36
 
37
- def add_job(self, task: Union[Callable[..., Any], str], *parameters: Any) -> Job:
37
+ def add_job(
38
+ self,
39
+ task: Union[Callable[..., Any], str],
40
+ *parameters: Any,
41
+ **parameters_keyed: Any,
42
+ ) -> Job:
38
43
  """
39
44
  Add a job to the queue with the given task and parameters.
40
45
 
41
46
  :param task: Either a function or a string with the task name
42
- :param parameters: Parameters to pass to the task
47
+ :param parameters: Positional parameters to pass to the task
48
+ :param parameters_keyed: Keyword parameters to pass to the task
43
49
  :returns: The created job
44
50
  :raises Exception: If something goes wrong
45
51
  """
46
52
  options: Optional[Options] = self._merge_options(None)
47
- job: Job = self._add_job(task, options, *parameters)
53
+ job: Job = self._add_job(task, options, *parameters, **parameters_keyed)
48
54
 
49
55
  logger.info(f"Job added: {job.rid}")
50
56
 
@@ -55,6 +61,7 @@ class QueuerJobMixin(QueuerGlobalMixin):
55
61
  options: Optional[Options],
56
62
  task: Union[Callable[..., Any], str],
57
63
  *parameters: Any,
64
+ **parameters_keyed: Any,
58
65
  ) -> Job:
59
66
  """Add a new job with specific options."""
60
67
  # Merge default options with provided options
@@ -62,7 +69,9 @@ class QueuerJobMixin(QueuerGlobalMixin):
62
69
 
63
70
  try:
64
71
  # Create new job
65
- new_job: Job = create_job(task, options_merged, *parameters)
72
+ new_job: Job = create_job(
73
+ task, options_merged, *parameters, **parameters_keyed
74
+ )
66
75
  job: Job = self.db_job.insert_job(new_job)
67
76
 
68
77
  logger.info(f"Job with options added: {job.rid}")
@@ -82,7 +91,9 @@ class QueuerJobMixin(QueuerGlobalMixin):
82
91
  for batch_job in batch_jobs:
83
92
  options: Optional[Options] = self._merge_options(batch_job.options)
84
93
  task_name: str = get_task_name_from_interface(batch_job.task)
85
- job: Job = create_job(task_name, options, *batch_job.parameters)
94
+ job: Job = create_job(
95
+ task_name, options, *batch_job.parameters, **batch_job.parameters_keyed
96
+ )
86
97
  jobs.append(job)
87
98
 
88
99
  self.db_job.batch_insert_jobs(jobs)
@@ -232,7 +243,9 @@ class QueuerJobMixin(QueuerGlobalMixin):
232
243
  raise Exception(f"Job not found in archive: {job_rid}")
233
244
 
234
245
  # Readd the job to the queue
235
- new_job = self.add_job_with_options(job.options, job.task_name, *job.parameters)
246
+ new_job = self.add_job_with_options(
247
+ job.options, job.task_name, *job.parameters, **job.parameters_keyed
248
+ )
236
249
  logger.info(f"Job readded: {new_job.rid}")
237
250
  return new_job
238
251
 
@@ -317,18 +330,20 @@ class QueuerJobMixin(QueuerGlobalMixin):
317
330
  task: Union[Callable[..., Any], str],
318
331
  options: Optional["Options"],
319
332
  *parameters: Any,
333
+ **parameters_keyed: Any,
320
334
  ) -> Job:
321
335
  """
322
336
  Add a job to the queue with all necessary parameters.
323
337
 
324
338
  :param task: Either a function or a string with the task name
325
339
  :param options: Job-specific options (can be None)
326
- :param parameters: Parameters to pass to the task
340
+ :param parameters: Positional parameters to pass to the task
341
+ :param parameters_keyed: Keyword parameters to pass to the task
327
342
  :returns: The created job
328
343
  :raises Exception: If something goes wrong
329
344
  """
330
345
  try:
331
- new_job = create_job(task, options, *parameters)
346
+ new_job = create_job(task, options, *parameters, **parameters_keyed)
332
347
  job = self.db_job.insert_job(new_job)
333
348
 
334
349
  return job
@@ -405,7 +420,8 @@ class QueuerJobMixin(QueuerGlobalMixin):
405
420
 
406
421
  try:
407
422
  parameters = getattr(job, "parameters", [])
408
- runner = Runner(task, *parameters)
423
+ parameters_keyed = getattr(job, "parameters_keyed", {})
424
+ runner = Runner(task, *parameters, **parameters_keyed)
409
425
 
410
426
  logger.info(f"Created runner for job {job.rid}")
411
427
 
@@ -15,6 +15,9 @@ BEGIN
15
15
  options JSONB DEFAULT '{}',
16
16
  task_name VARCHAR(100) DEFAULT '',
17
17
  parameters JSONB DEFAULT '[]',
18
+ parameters_encrypted BYTEA DEFAULT '',
19
+ parameters_keyed JSONB DEFAULT '{}',
20
+ parameters_keyed_encrypted BYTEA DEFAULT '',
18
21
  status VARCHAR(50) DEFAULT 'QUEUED',
19
22
  scheduled_at TIMESTAMP DEFAULT NULL,
20
23
  started_at TIMESTAMP DEFAULT NULL,
@@ -62,6 +65,7 @@ CREATE OR REPLACE FUNCTION insert_job(
62
65
  input_options JSONB,
63
66
  input_task_name VARCHAR(100),
64
67
  input_parameters JSONB,
68
+ input_parameters_keyed JSONB,
65
69
  input_status VARCHAR(50),
66
70
  input_scheduled_at TIMESTAMP,
67
71
  input_schedule_count INT
@@ -74,6 +78,7 @@ RETURNS TABLE (
74
78
  output_options JSONB,
75
79
  output_task_name VARCHAR(100),
76
80
  output_parameters JSONB,
81
+ output_parameters_keyed JSONB,
77
82
  output_status VARCHAR(50),
78
83
  output_scheduled_at TIMESTAMP,
79
84
  output_schedule_count INT,
@@ -84,8 +89,8 @@ RETURNS TABLE (
84
89
  AS $$
85
90
  BEGIN
86
91
  RETURN QUERY
87
- INSERT INTO job (options, task_name, parameters, status, scheduled_at, schedule_count)
88
- VALUES (input_options, input_task_name, input_parameters, input_status, input_scheduled_at, input_schedule_count)
92
+ INSERT INTO job (options, task_name, parameters, parameters_keyed, status, scheduled_at, schedule_count)
93
+ VALUES (input_options, input_task_name, input_parameters, input_parameters_keyed, input_status, input_scheduled_at, input_schedule_count)
89
94
  RETURNING
90
95
  job.id,
91
96
  job.rid,
@@ -94,6 +99,7 @@ BEGIN
94
99
  job.options,
95
100
  job.task_name,
96
101
  job.parameters,
102
+ job.parameters_keyed,
97
103
  job.status,
98
104
  job.scheduled_at,
99
105
  job.schedule_count,
@@ -112,6 +118,7 @@ RETURNS TABLE (
112
118
  output_options JSONB,
113
119
  output_task_name VARCHAR(100),
114
120
  output_parameters JSONB,
121
+ output_parameters_keyed JSONB,
115
122
  output_status VARCHAR(50),
116
123
  output_scheduled_at TIMESTAMP,
117
124
  output_started_at TIMESTAMP,
@@ -182,6 +189,7 @@ BEGIN
182
189
  job.options,
183
190
  job.task_name,
184
191
  job.parameters,
192
+ job.parameters_keyed,
185
193
  job.status,
186
194
  job.scheduled_at,
187
195
  job.started_at,
@@ -206,6 +214,7 @@ RETURNS TABLE (
206
214
  output_options JSONB,
207
215
  output_task_name VARCHAR(100),
208
216
  output_parameters JSONB,
217
+ output_parameters_keyed JSONB,
209
218
  output_status VARCHAR(50),
210
219
  output_scheduled_at TIMESTAMP,
211
220
  output_started_at TIMESTAMP,
@@ -229,6 +238,9 @@ BEGIN
229
238
  options,
230
239
  task_name,
231
240
  parameters,
241
+ parameters_encrypted,
242
+ parameters_keyed,
243
+ parameters_keyed_encrypted,
232
244
  scheduled_at,
233
245
  started_at,
234
246
  schedule_count,
@@ -244,6 +256,9 @@ BEGIN
244
256
  options,
245
257
  task_name,
246
258
  parameters,
259
+ parameters_encrypted,
260
+ parameters_keyed,
261
+ parameters_keyed_encrypted,
247
262
  status,
248
263
  scheduled_at,
249
264
  started_at,
@@ -262,6 +277,9 @@ BEGIN
262
277
  jobs_old.options,
263
278
  jobs_old.task_name,
264
279
  jobs_old.parameters,
280
+ jobs_old.parameters_encrypted,
281
+ jobs_old.parameters_keyed,
282
+ jobs_old.parameters_keyed_encrypted,
265
283
  input_status,
266
284
  jobs_old.scheduled_at,
267
285
  jobs_old.started_at,
@@ -280,6 +298,7 @@ BEGIN
280
298
  options,
281
299
  task_name,
282
300
  parameters,
301
+ parameters_keyed,
283
302
  status,
284
303
  scheduled_at,
285
304
  started_at,
@@ -307,6 +326,7 @@ RETURNS TABLE (
307
326
  output_options JSONB,
308
327
  output_task_name VARCHAR(100),
309
328
  output_parameters JSONB,
329
+ output_parameters_keyed JSONB,
310
330
  output_status VARCHAR(50),
311
331
  output_scheduled_at TIMESTAMP,
312
332
  output_started_at TIMESTAMP,
@@ -330,6 +350,9 @@ BEGIN
330
350
  options,
331
351
  task_name,
332
352
  parameters,
353
+ parameters_encrypted,
354
+ parameters_keyed,
355
+ parameters_keyed_encrypted,
333
356
  scheduled_at,
334
357
  started_at,
335
358
  schedule_count,
@@ -345,6 +368,9 @@ BEGIN
345
368
  options,
346
369
  task_name,
347
370
  parameters,
371
+ parameters_encrypted,
372
+ parameters_keyed,
373
+ parameters_keyed_encrypted,
348
374
  status,
349
375
  scheduled_at,
350
376
  started_at,
@@ -363,6 +389,9 @@ BEGIN
363
389
  jobs_old.options,
364
390
  jobs_old.task_name,
365
391
  jobs_old.parameters,
392
+ jobs_old.parameters_encrypted,
393
+ jobs_old.parameters_keyed,
394
+ jobs_old.parameters_keyed_encrypted,
366
395
  input_status,
367
396
  jobs_old.scheduled_at,
368
397
  jobs_old.started_at,
@@ -381,6 +410,7 @@ BEGIN
381
410
  options,
382
411
  task_name,
383
412
  parameters,
413
+ parameters_keyed,
384
414
  status,
385
415
  scheduled_at,
386
416
  started_at,
@@ -419,13 +449,6 @@ BEGIN
419
449
  END;
420
450
  $$ LANGUAGE plpgsql;
421
451
 
422
- CREATE OR REPLACE FUNCTION delete_job(input_rid UUID)
423
- RETURNS VOID AS $$
424
- BEGIN
425
- DELETE FROM job WHERE rid = input_rid;
426
- END;
427
- $$ LANGUAGE plpgsql;
428
-
429
452
  CREATE OR REPLACE FUNCTION select_job(input_encryption_key TEXT, input_rid UUID)
430
453
  RETURNS TABLE (
431
454
  output_id BIGINT,
@@ -435,6 +458,7 @@ RETURNS TABLE (
435
458
  output_options JSONB,
436
459
  output_task_name VARCHAR(100),
437
460
  output_parameters JSONB,
461
+ output_parameters_keyed JSONB,
438
462
  output_status VARCHAR(50),
439
463
  output_scheduled_at TIMESTAMP,
440
464
  output_started_at TIMESTAMP,
@@ -454,7 +478,14 @@ BEGIN
454
478
  job.worker_rid,
455
479
  job.options,
456
480
  job.task_name,
457
- job.parameters,
481
+ CASE
482
+ WHEN octet_length(job.parameters_encrypted) > 0 THEN pgp_sym_decrypt(job.parameters_encrypted, input_encryption_key::text)::jsonb
483
+ ELSE job.parameters
484
+ END AS parameters,
485
+ CASE
486
+ WHEN octet_length(job.parameters_keyed_encrypted) > 0 THEN pgp_sym_decrypt(job.parameters_keyed_encrypted, input_encryption_key::text)::jsonb
487
+ ELSE job.parameters_keyed
488
+ END AS parameters_keyed,
458
489
  job.status,
459
490
  job.scheduled_at,
460
491
  job.started_at,
@@ -481,6 +512,7 @@ RETURNS TABLE (
481
512
  output_options JSONB,
482
513
  output_task_name VARCHAR(100),
483
514
  output_parameters JSONB,
515
+ output_parameters_keyed JSONB,
484
516
  output_status VARCHAR(50),
485
517
  output_scheduled_at TIMESTAMP,
486
518
  output_started_at TIMESTAMP,
@@ -500,7 +532,14 @@ BEGIN
500
532
  job.worker_rid,
501
533
  job.options,
502
534
  job.task_name,
503
- job.parameters,
535
+ CASE
536
+ WHEN octet_length(job.parameters_encrypted) > 0 THEN pgp_sym_decrypt(job.parameters_encrypted, input_encryption_key::text)::jsonb
537
+ ELSE job.parameters
538
+ END AS parameters,
539
+ CASE
540
+ WHEN octet_length(job.parameters_keyed_encrypted) > 0 THEN pgp_sym_decrypt(job.parameters_keyed_encrypted, input_encryption_key::text)::jsonb
541
+ ELSE job.parameters_keyed
542
+ END AS parameters_keyed,
504
543
  job.status,
505
544
  job.scheduled_at,
506
545
  job.started_at,
@@ -538,6 +577,7 @@ RETURNS TABLE (
538
577
  output_options JSONB,
539
578
  output_task_name VARCHAR(100),
540
579
  output_parameters JSONB,
580
+ output_parameters_keyed JSONB,
541
581
  output_status VARCHAR(50),
542
582
  output_scheduled_at TIMESTAMP,
543
583
  output_started_at TIMESTAMP,
@@ -557,7 +597,14 @@ BEGIN
557
597
  job.worker_rid,
558
598
  job.options,
559
599
  job.task_name,
560
- job.parameters,
600
+ CASE
601
+ WHEN octet_length(job.parameters_encrypted) > 0 THEN pgp_sym_decrypt(job.parameters_encrypted, input_encryption_key::text)::jsonb
602
+ ELSE job.parameters
603
+ END AS parameters,
604
+ CASE
605
+ WHEN octet_length(job.parameters_keyed_encrypted) > 0 THEN pgp_sym_decrypt(job.parameters_keyed_encrypted, input_encryption_key::text)::jsonb
606
+ ELSE job.parameters_keyed
607
+ END AS parameters_keyed,
561
608
  job.status,
562
609
  job.scheduled_at,
563
610
  job.started_at,
@@ -596,6 +643,7 @@ RETURNS TABLE (
596
643
  output_options JSONB,
597
644
  output_task_name VARCHAR(100),
598
645
  output_parameters JSONB,
646
+ output_parameters_keyed JSONB,
599
647
  output_status VARCHAR(50),
600
648
  output_scheduled_at TIMESTAMP,
601
649
  output_started_at TIMESTAMP,
@@ -615,7 +663,14 @@ BEGIN
615
663
  job.worker_rid,
616
664
  job.options,
617
665
  job.task_name,
618
- job.parameters,
666
+ CASE
667
+ WHEN octet_length(job.parameters_encrypted) > 0 THEN pgp_sym_decrypt(job.parameters_encrypted, input_encryption_key::text)::jsonb
668
+ ELSE job.parameters
669
+ END AS parameters,
670
+ CASE
671
+ WHEN octet_length(job.parameters_keyed_encrypted) > 0 THEN pgp_sym_decrypt(job.parameters_keyed_encrypted, input_encryption_key::text)::jsonb
672
+ ELSE job.parameters_keyed
673
+ END AS parameters_keyed,
619
674
  job.status,
620
675
  job.scheduled_at,
621
676
  job.started_at,
@@ -657,6 +712,13 @@ BEGIN
657
712
  END;
658
713
  $$ LANGUAGE plpgsql;
659
714
 
715
+ CREATE OR REPLACE FUNCTION delete_job(input_rid UUID)
716
+ RETURNS VOID AS $$
717
+ BEGIN
718
+ DELETE FROM job_archive WHERE rid = input_rid;
719
+ END;
720
+ $$ LANGUAGE plpgsql;
721
+
660
722
  CREATE OR REPLACE FUNCTION select_job_from_archive(input_encryption_key TEXT, input_rid UUID)
661
723
  RETURNS TABLE (
662
724
  output_id BIGINT,
@@ -666,6 +728,7 @@ RETURNS TABLE (
666
728
  output_options JSONB,
667
729
  output_task_name VARCHAR(100),
668
730
  output_parameters JSONB,
731
+ output_parameters_keyed JSONB,
669
732
  output_status VARCHAR(50),
670
733
  output_scheduled_at TIMESTAMP,
671
734
  output_started_at TIMESTAMP,
@@ -685,7 +748,14 @@ BEGIN
685
748
  job_archive.worker_rid,
686
749
  job_archive.options,
687
750
  job_archive.task_name,
688
- job_archive.parameters,
751
+ CASE
752
+ WHEN octet_length(job_archive.parameters_encrypted) > 0 THEN pgp_sym_decrypt(job_archive.parameters_encrypted, input_encryption_key::text)::jsonb
753
+ ELSE job_archive.parameters
754
+ END AS parameters,
755
+ CASE
756
+ WHEN octet_length(job_archive.parameters_keyed_encrypted) > 0 THEN pgp_sym_decrypt(job_archive.parameters_keyed_encrypted, input_encryption_key::text)::jsonb
757
+ ELSE job_archive.parameters_keyed
758
+ END AS parameters_keyed,
689
759
  job_archive.status,
690
760
  job_archive.scheduled_at,
691
761
  job_archive.started_at,
@@ -712,6 +782,7 @@ RETURNS TABLE (
712
782
  output_options JSONB,
713
783
  output_task_name VARCHAR(100),
714
784
  output_parameters JSONB,
785
+ output_parameters_keyed JSONB,
715
786
  output_status VARCHAR(50),
716
787
  output_scheduled_at TIMESTAMP,
717
788
  output_started_at TIMESTAMP,
@@ -731,7 +802,14 @@ BEGIN
731
802
  job_archive.worker_rid,
732
803
  job_archive.options,
733
804
  job_archive.task_name,
734
- job_archive.parameters,
805
+ CASE
806
+ WHEN octet_length(job_archive.parameters_encrypted) > 0 THEN pgp_sym_decrypt(job_archive.parameters_encrypted, input_encryption_key::text)::jsonb
807
+ ELSE job_archive.parameters
808
+ END AS parameters,
809
+ CASE
810
+ WHEN octet_length(job_archive.parameters_keyed_encrypted) > 0 THEN pgp_sym_decrypt(job_archive.parameters_keyed_encrypted, input_encryption_key::text)::jsonb
811
+ ELSE job_archive.parameters_keyed
812
+ END AS parameters_keyed,
735
813
  job_archive.status,
736
814
  job_archive.scheduled_at,
737
815
  job_archive.started_at,
@@ -769,6 +847,7 @@ RETURNS TABLE (
769
847
  output_options JSONB,
770
848
  output_task_name VARCHAR(100),
771
849
  output_parameters JSONB,
850
+ output_parameters_keyed JSONB,
772
851
  output_status VARCHAR(50),
773
852
  output_scheduled_at TIMESTAMP,
774
853
  output_started_at TIMESTAMP,
@@ -788,7 +867,14 @@ BEGIN
788
867
  job_archive.worker_rid,
789
868
  job_archive.options,
790
869
  job_archive.task_name,
791
- job_archive.parameters,
870
+ CASE
871
+ WHEN octet_length(job_archive.parameters_encrypted) > 0 THEN pgp_sym_decrypt(job_archive.parameters_encrypted, input_encryption_key::text)::jsonb
872
+ ELSE job_archive.parameters
873
+ END AS parameters,
874
+ CASE
875
+ WHEN octet_length(job_archive.parameters_keyed_encrypted) > 0 THEN pgp_sym_decrypt(job_archive.parameters_keyed_encrypted, input_encryption_key::text)::jsonb
876
+ ELSE job_archive.parameters_keyed
877
+ END AS parameters_keyed,
792
878
  job_archive.status,
793
879
  job_archive.scheduled_at,
794
880
  job_archive.started_at,
@@ -138,6 +138,23 @@ BEGIN
138
138
  END;
139
139
  $$ LANGUAGE plpgsql;
140
140
 
141
+ CREATE OR REPLACE FUNCTION delete_stale_workers(
142
+ input_cutoff_time TIMESTAMP
143
+ )
144
+ RETURNS INT
145
+ AS $$
146
+ DECLARE
147
+ affected_rows INT;
148
+ BEGIN
149
+ DELETE FROM worker
150
+ WHERE updated_at < input_cutoff_time
151
+ AND status = 'STOPPED';
152
+
153
+ GET DIAGNOSTICS affected_rows = ROW_COUNT;
154
+ RETURN affected_rows;
155
+ END;
156
+ $$ LANGUAGE plpgsql;
157
+
141
158
  CREATE OR REPLACE FUNCTION select_worker(input_rid UUID)
142
159
  RETURNS TABLE (
143
160
  output_id BIGINT,
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes