queuerPy 0.6.0__tar.gz → 0.8.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 (51) hide show
  1. {queuerpy-0.6.0/queuerPy.egg-info → queuerpy-0.8.0}/PKG-INFO +22 -9
  2. {queuerpy-0.6.0 → queuerpy-0.8.0}/README.md +21 -8
  3. {queuerpy-0.6.0 → queuerpy-0.8.0}/_version.py +1 -1
  4. {queuerpy-0.6.0 → queuerpy-0.8.0}/database/db_job.py +35 -11
  5. {queuerpy-0.6.0 → queuerpy-0.8.0}/pyproject.toml +1 -1
  6. {queuerpy-0.6.0 → queuerpy-0.8.0/queuerPy.egg-info}/PKG-INFO +22 -9
  7. {queuerpy-0.6.0 → queuerpy-0.8.0}/queuer_job.py +3 -5
  8. {queuerpy-0.6.0 → queuerpy-0.8.0}/queuer_task.py +37 -1
  9. {queuerpy-0.6.0 → queuerpy-0.8.0}/LICENSE +0 -0
  10. {queuerpy-0.6.0 → queuerpy-0.8.0}/MANIFEST.in +0 -0
  11. {queuerpy-0.6.0 → queuerpy-0.8.0}/__init__.py +0 -0
  12. {queuerpy-0.6.0 → queuerpy-0.8.0}/core/__init__.py +0 -0
  13. {queuerpy-0.6.0 → queuerpy-0.8.0}/core/broadcaster.py +0 -0
  14. {queuerpy-0.6.0 → queuerpy-0.8.0}/core/listener.py +0 -0
  15. {queuerpy-0.6.0 → queuerpy-0.8.0}/core/retryer.py +0 -0
  16. {queuerpy-0.6.0 → queuerpy-0.8.0}/core/runner.py +0 -0
  17. {queuerpy-0.6.0 → queuerpy-0.8.0}/core/scheduler.py +0 -0
  18. {queuerpy-0.6.0 → queuerpy-0.8.0}/core/ticker.py +0 -0
  19. {queuerpy-0.6.0 → queuerpy-0.8.0}/database/__init__.py +0 -0
  20. {queuerpy-0.6.0 → queuerpy-0.8.0}/database/db_listener.py +0 -0
  21. {queuerpy-0.6.0 → queuerpy-0.8.0}/database/db_master.py +0 -0
  22. {queuerpy-0.6.0 → queuerpy-0.8.0}/database/db_worker.py +0 -0
  23. {queuerpy-0.6.0 → queuerpy-0.8.0}/helper/__init__.py +0 -0
  24. {queuerpy-0.6.0 → queuerpy-0.8.0}/helper/database.py +0 -0
  25. {queuerpy-0.6.0 → queuerpy-0.8.0}/helper/error.py +0 -0
  26. {queuerpy-0.6.0 → queuerpy-0.8.0}/helper/logging.py +0 -0
  27. {queuerpy-0.6.0 → queuerpy-0.8.0}/helper/sql.py +0 -0
  28. {queuerpy-0.6.0 → queuerpy-0.8.0}/helper/task.py +0 -0
  29. {queuerpy-0.6.0 → queuerpy-0.8.0}/model/__init__.py +0 -0
  30. {queuerpy-0.6.0 → queuerpy-0.8.0}/model/batch_job.py +0 -0
  31. {queuerpy-0.6.0 → queuerpy-0.8.0}/model/connection.py +0 -0
  32. {queuerpy-0.6.0 → queuerpy-0.8.0}/model/job.py +0 -0
  33. {queuerpy-0.6.0 → queuerpy-0.8.0}/model/master.py +0 -0
  34. {queuerpy-0.6.0 → queuerpy-0.8.0}/model/options.py +0 -0
  35. {queuerpy-0.6.0 → queuerpy-0.8.0}/model/options_on_error.py +0 -0
  36. {queuerpy-0.6.0 → queuerpy-0.8.0}/model/task.py +0 -0
  37. {queuerpy-0.6.0 → queuerpy-0.8.0}/model/worker.py +0 -0
  38. {queuerpy-0.6.0 → queuerpy-0.8.0}/queuer.py +0 -0
  39. {queuerpy-0.6.0 → queuerpy-0.8.0}/queuerPy.egg-info/SOURCES.txt +0 -0
  40. {queuerpy-0.6.0 → queuerpy-0.8.0}/queuerPy.egg-info/dependency_links.txt +0 -0
  41. {queuerpy-0.6.0 → queuerpy-0.8.0}/queuerPy.egg-info/requires.txt +0 -0
  42. {queuerpy-0.6.0 → queuerpy-0.8.0}/queuerPy.egg-info/top_level.txt +0 -0
  43. {queuerpy-0.6.0 → queuerpy-0.8.0}/queuer_global.py +0 -0
  44. {queuerpy-0.6.0 → queuerpy-0.8.0}/queuer_listener.py +0 -0
  45. {queuerpy-0.6.0 → queuerpy-0.8.0}/queuer_master.py +0 -0
  46. {queuerpy-0.6.0 → queuerpy-0.8.0}/queuer_next_interval.py +0 -0
  47. {queuerpy-0.6.0 → queuerpy-0.8.0}/setup.cfg +0 -0
  48. {queuerpy-0.6.0 → queuerpy-0.8.0}/sql/job.sql +0 -0
  49. {queuerpy-0.6.0 → queuerpy-0.8.0}/sql/master.sql +0 -0
  50. {queuerpy-0.6.0 → queuerpy-0.8.0}/sql/notify.sql +0 -0
  51. {queuerpy-0.6.0 → queuerpy-0.8.0}/sql/worker.sql +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: queuerPy
3
- Version: 0.6.0
3
+ Version: 0.8.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>
@@ -86,6 +86,14 @@ q.add_task(example_task)
86
86
  q.start()
87
87
  ```
88
88
 
89
+ You can also add a task with a decorator so the tasks don't have to be added to some central function:
90
+
91
+ ```python
92
+ @queuer.task(name="optionalName")
93
+ def example_task():
94
+ ...
95
+ ```
96
+
89
97
  That's easy, right? Adding a job is just as easy:
90
98
 
91
99
  ```python
@@ -329,19 +337,24 @@ worker_jobs = queuer.get_jobs_by_worker_rid(worker.rid)
329
337
 
330
338
  - **Async/Await Support**: Full asyncio integration with threading fallbacks.
331
339
  - **PostgreSQL NOTIFY/LISTEN**: Real-time job notifications without polling overhead.
332
- - **Batch Job Processing**: Insert job batches efficiently.
333
- - **Transaction Support**: Insert jobs within transactions for rollback capability.
334
- - **Error Recovery**: Comprehensive error handling and retry mechanisms.
335
- - **Multiple Workers**: Multiple queuer instances can run across different services while maintaining job order and isolation.
340
+ - **Batch Job Processing**: Insert job batches efficiently using PostgreSQL's `COPY FROM` feature.
341
+ - **Panic Recovery**: Automatic recovery for all running jobs in case of unexpected failures.
342
+ - **Error Handling**: Comprehensive error handling by checking last output parameter for errors.
343
+ - **Multiple Workers**: Multiple queuer instances can run across different microservices while maintaining job start order and isolation.
336
344
  - **Scheduled Jobs**: Support for scheduled and periodic jobs with custom intervals.
337
345
  - **Job Lifecycle Management**: Easy functions to get jobs and workers, track job status.
338
- - **Event Listeners**: Listen for job updates, completion, and deletion events.
339
- - **Retry Mechanisms**: Configurable retry logic with different backoff strategies.
340
- - **Custom Scheduling**: Custom NextInterval functions for complex scheduling needs.
341
- - **Heartbeat System**: Worker heartbeat monitoring and automatic cleanup of stale workers.
346
+ - **Event Listeners**: Listen for job updates, completion, and deletion events (ended jobs).
347
+ - **Job Completion Helpers**: Helper functions to listen for specific finished jobs.
348
+ - **Retry Mechanisms**: Retry mechanism for ended jobs which creates a new job with the same parameters, with configurable retry logic and different backoff strategies.
349
+ - **Custom Scheduling**: Custom NextInterval functions to address custom needs for scheduling (e.g., scheduling with timezone offset).
350
+ - **Master Worker Management**: Automatic master worker setting retention and other central settings. Automatic switch to new master if old worker stops.
351
+ - **Heartbeat System**: Worker heartbeat monitoring and automatic stale worker detection and cancellation by the master.
352
+ - **Encryption Support**: Encryption support for sensitive job data stored in the database.
342
353
  - **Database Integration**: Seamless PostgreSQL integration with automatic schema management.
343
354
  - **Type Safety**: Full type hints and dataclass-based models for better development experience.
344
355
 
356
+ > **Note**: Transactional job insert is the only feature that is not yet implemented in the Python implementation of the queuer.
357
+
345
358
  ---
346
359
 
347
360
  # 🧪 Testing
@@ -43,6 +43,14 @@ q.add_task(example_task)
43
43
  q.start()
44
44
  ```
45
45
 
46
+ You can also add a task with a decorator so the tasks don't have to be added to some central function:
47
+
48
+ ```python
49
+ @queuer.task(name="optionalName")
50
+ def example_task():
51
+ ...
52
+ ```
53
+
46
54
  That's easy, right? Adding a job is just as easy:
47
55
 
48
56
  ```python
@@ -286,19 +294,24 @@ worker_jobs = queuer.get_jobs_by_worker_rid(worker.rid)
286
294
 
287
295
  - **Async/Await Support**: Full asyncio integration with threading fallbacks.
288
296
  - **PostgreSQL NOTIFY/LISTEN**: Real-time job notifications without polling overhead.
289
- - **Batch Job Processing**: Insert job batches efficiently.
290
- - **Transaction Support**: Insert jobs within transactions for rollback capability.
291
- - **Error Recovery**: Comprehensive error handling and retry mechanisms.
292
- - **Multiple Workers**: Multiple queuer instances can run across different services while maintaining job order and isolation.
297
+ - **Batch Job Processing**: Insert job batches efficiently using PostgreSQL's `COPY FROM` feature.
298
+ - **Panic Recovery**: Automatic recovery for all running jobs in case of unexpected failures.
299
+ - **Error Handling**: Comprehensive error handling by checking last output parameter for errors.
300
+ - **Multiple Workers**: Multiple queuer instances can run across different microservices while maintaining job start order and isolation.
293
301
  - **Scheduled Jobs**: Support for scheduled and periodic jobs with custom intervals.
294
302
  - **Job Lifecycle Management**: Easy functions to get jobs and workers, track job status.
295
- - **Event Listeners**: Listen for job updates, completion, and deletion events.
296
- - **Retry Mechanisms**: Configurable retry logic with different backoff strategies.
297
- - **Custom Scheduling**: Custom NextInterval functions for complex scheduling needs.
298
- - **Heartbeat System**: Worker heartbeat monitoring and automatic cleanup of stale workers.
303
+ - **Event Listeners**: Listen for job updates, completion, and deletion events (ended jobs).
304
+ - **Job Completion Helpers**: Helper functions to listen for specific finished jobs.
305
+ - **Retry Mechanisms**: Retry mechanism for ended jobs which creates a new job with the same parameters, with configurable retry logic and different backoff strategies.
306
+ - **Custom Scheduling**: Custom NextInterval functions to address custom needs for scheduling (e.g., scheduling with timezone offset).
307
+ - **Master Worker Management**: Automatic master worker setting retention and other central settings. Automatic switch to new master if old worker stops.
308
+ - **Heartbeat System**: Worker heartbeat monitoring and automatic stale worker detection and cancellation by the master.
309
+ - **Encryption Support**: Encryption support for sensitive job data stored in the database.
299
310
  - **Database Integration**: Seamless PostgreSQL integration with automatic schema management.
300
311
  - **Type Safety**: Full type hints and dataclass-based models for better development experience.
301
312
 
313
+ > **Note**: Transactional job insert is the only feature that is not yet implemented in the Python implementation of the queuer.
314
+
302
315
  ---
303
316
 
304
317
  # 🧪 Testing
@@ -1,6 +1,6 @@
1
1
  """Version information for queuerPy package."""
2
2
 
3
- __version__ = "0.6.0"
3
+ __version__ = "0.8.0"
4
4
  __version_info__ = tuple(int(part) for part in __version__.split("."))
5
5
 
6
6
  # For compatibility
@@ -3,8 +3,9 @@ Job database handler for Python queuer implementation.
3
3
  Mirrors Go's database/dbJob.go with psycopg3 and references same SQL functions.
4
4
  """
5
5
 
6
+ from datetime import datetime
6
7
  import json
7
- from typing import List, Optional
8
+ from typing import List, Optional, Tuple
8
9
  from uuid import UUID
9
10
  from psycopg.rows import dict_row
10
11
 
@@ -127,21 +128,44 @@ class JobDBHandler:
127
128
  # In full implementation, this would handle explicit transaction context
128
129
  return self.insert_job(job)
129
130
 
130
- def batch_insert_jobs(self, jobs: List[Job]) -> List[Job]:
131
+ def batch_insert_jobs(self, jobs: List[Job]):
131
132
  """
132
- Insert multiple jobs in a batch operation.
133
- Placeholder method - mirrors Go's BatchInsertJobs method.
134
- TODO: Implement efficient batch insert logic.
133
+ Insert multiple jobs in a batch operation using executemany.
134
+ Mirrors Go's BatchInsertJobs method with direct INSERT statements.
135
135
 
136
136
  :param jobs: List of Job instances to insert.
137
137
  :return: List of inserted Job instances.
138
+ :raises QueuerError: If batch insertion fails.
138
139
  """
139
- # For now, insert jobs one by one
140
- # In full implementation, this would use batch SQL operations
141
- result_jobs: List[Job] = []
142
- for job in jobs:
143
- result_jobs.append(self.insert_job(job))
144
- return result_jobs
140
+ if not jobs:
141
+ return
142
+
143
+ if self.db.instance is None:
144
+ raise ValueError("Database connection is not established")
145
+
146
+ try:
147
+ batch_data: List[Tuple[str, str, str, Optional[datetime]]] = []
148
+ for job in jobs:
149
+ options_json = (
150
+ json.dumps(job.options.to_dict()) if job.options else "{}"
151
+ )
152
+ parameters_json = json.dumps(job.parameters)
153
+ batch_data.append(
154
+ (options_json, job.task_name, parameters_json, job.scheduled_at)
155
+ )
156
+
157
+ with self.db.instance.cursor(row_factory=dict_row) as cur:
158
+ cur.executemany(
159
+ """
160
+ INSERT INTO job (options, task_name, parameters, scheduled_at)
161
+ VALUES (%s, %s, %s, %s)
162
+ """,
163
+ batch_data,
164
+ )
165
+ self.db.instance.commit()
166
+ except Exception as e:
167
+ self.db.instance.rollback()
168
+ raise QueuerError("batch insert jobs", e)
145
169
 
146
170
  def update_jobs_initial(self, worker: Worker) -> List[Job]:
147
171
  """
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "queuerPy"
7
- version = "0.6.0"
7
+ version = "0.8.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"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: queuerPy
3
- Version: 0.6.0
3
+ Version: 0.8.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>
@@ -86,6 +86,14 @@ q.add_task(example_task)
86
86
  q.start()
87
87
  ```
88
88
 
89
+ You can also add a task with a decorator so the tasks don't have to be added to some central function:
90
+
91
+ ```python
92
+ @queuer.task(name="optionalName")
93
+ def example_task():
94
+ ...
95
+ ```
96
+
89
97
  That's easy, right? Adding a job is just as easy:
90
98
 
91
99
  ```python
@@ -329,19 +337,24 @@ worker_jobs = queuer.get_jobs_by_worker_rid(worker.rid)
329
337
 
330
338
  - **Async/Await Support**: Full asyncio integration with threading fallbacks.
331
339
  - **PostgreSQL NOTIFY/LISTEN**: Real-time job notifications without polling overhead.
332
- - **Batch Job Processing**: Insert job batches efficiently.
333
- - **Transaction Support**: Insert jobs within transactions for rollback capability.
334
- - **Error Recovery**: Comprehensive error handling and retry mechanisms.
335
- - **Multiple Workers**: Multiple queuer instances can run across different services while maintaining job order and isolation.
340
+ - **Batch Job Processing**: Insert job batches efficiently using PostgreSQL's `COPY FROM` feature.
341
+ - **Panic Recovery**: Automatic recovery for all running jobs in case of unexpected failures.
342
+ - **Error Handling**: Comprehensive error handling by checking last output parameter for errors.
343
+ - **Multiple Workers**: Multiple queuer instances can run across different microservices while maintaining job start order and isolation.
336
344
  - **Scheduled Jobs**: Support for scheduled and periodic jobs with custom intervals.
337
345
  - **Job Lifecycle Management**: Easy functions to get jobs and workers, track job status.
338
- - **Event Listeners**: Listen for job updates, completion, and deletion events.
339
- - **Retry Mechanisms**: Configurable retry logic with different backoff strategies.
340
- - **Custom Scheduling**: Custom NextInterval functions for complex scheduling needs.
341
- - **Heartbeat System**: Worker heartbeat monitoring and automatic cleanup of stale workers.
346
+ - **Event Listeners**: Listen for job updates, completion, and deletion events (ended jobs).
347
+ - **Job Completion Helpers**: Helper functions to listen for specific finished jobs.
348
+ - **Retry Mechanisms**: Retry mechanism for ended jobs which creates a new job with the same parameters, with configurable retry logic and different backoff strategies.
349
+ - **Custom Scheduling**: Custom NextInterval functions to address custom needs for scheduling (e.g., scheduling with timezone offset).
350
+ - **Master Worker Management**: Automatic master worker setting retention and other central settings. Automatic switch to new master if old worker stops.
351
+ - **Heartbeat System**: Worker heartbeat monitoring and automatic stale worker detection and cancellation by the master.
352
+ - **Encryption Support**: Encryption support for sensitive job data stored in the database.
342
353
  - **Database Integration**: Seamless PostgreSQL integration with automatic schema management.
343
354
  - **Type Safety**: Full type hints and dataclass-based models for better development experience.
344
355
 
356
+ > **Note**: Transactional job insert is the only feature that is not yet implemented in the Python implementation of the queuer.
357
+
345
358
  ---
346
359
 
347
360
  # 🧪 Testing
@@ -6,7 +6,7 @@ Mirrors Go's queuerJob.go functionality.
6
6
  import asyncio
7
7
  import logging
8
8
  from datetime import datetime
9
- from typing import Dict, List, Optional, Any, Tuple, Union, Callable, TYPE_CHECKING
9
+ from typing import Dict, List, Optional, Any, Tuple, Union, Callable
10
10
  from uuid import UUID
11
11
 
12
12
  from core.broadcaster import BroadcasterQueue
@@ -15,14 +15,12 @@ from core.retryer import Retryer
15
15
  from core.scheduler import Scheduler
16
16
  from helper.error import QueuerError
17
17
  from helper.task import get_task_name_from_interface
18
+ from model.batch_job import BatchJob
18
19
  from model.job import Job, JobStatus, new_job as create_job
19
20
  from model.options import Options
20
21
  from model.worker import Worker
21
22
  from queuer_global import QueuerGlobalMixin
22
23
 
23
- if TYPE_CHECKING:
24
- from model.batch_job import BatchJob
25
-
26
24
  # Set up logger
27
25
  logger = logging.getLogger(__name__)
28
26
 
@@ -73,7 +71,7 @@ class QueuerJobMixin(QueuerGlobalMixin):
73
71
  logger.error(f"Error adding job with options: {str(e)}")
74
72
  raise Exception(f"Adding job: {str(e)}")
75
73
 
76
- def add_jobs(self, batch_jobs: List["BatchJob"]):
74
+ def add_jobs(self, batch_jobs: List[BatchJob]):
77
75
  """
78
76
  Add a batch of jobs to the queue.
79
77
 
@@ -4,7 +4,7 @@ Mirrors Go's queuerTask.go functionality.
4
4
  """
5
5
 
6
6
  import logging
7
- from typing import Any, Callable, Optional
7
+ from typing import Any, Callable, Optional, TypeVar, overload
8
8
 
9
9
  from model.task import new_task, new_task_with_name
10
10
  from model.task import Task
@@ -12,6 +12,9 @@ from queuer_global import QueuerGlobalMixin
12
12
 
13
13
  logger = logging.getLogger(__name__)
14
14
 
15
+ # TypeVar for maintaining function type through decorator
16
+ F = TypeVar("F", bound=Callable[..., Any])
17
+
15
18
 
16
19
  class QueuerTaskMixin(QueuerGlobalMixin):
17
20
  """
@@ -87,3 +90,36 @@ class QueuerTaskMixin(QueuerGlobalMixin):
87
90
 
88
91
  logger.info(f"Task added: {new_task_obj.name}")
89
92
  return new_task_obj
93
+
94
+ @overload
95
+ def task(self, name: None = None) -> Callable[[F], F]: ...
96
+
97
+ @overload
98
+ def task(self, name: str) -> Callable[[F], F]: ...
99
+
100
+ def task(self, name: Optional[str] = None) -> Callable[[F], F]:
101
+ """
102
+ Decorator to register a task function with the queuer.
103
+ This is equivalent to calling add_task() or add_task_with_name().
104
+
105
+ Usage:
106
+ @queuer.task()
107
+ def my_task(param1, param2):
108
+ return param1 + param2
109
+
110
+ @queuer.task(name="custom_task_name")
111
+ def my_other_task(param):
112
+ return param * 2
113
+
114
+ :param name: Optional custom name for the task. If not provided, uses function name.
115
+ :return: The decorator function that preserves the original function's type
116
+ """
117
+
118
+ def decorator(func: F) -> F:
119
+ if name is not None:
120
+ self.add_task_with_name(func, name)
121
+ else:
122
+ self.add_task(func)
123
+ return func
124
+
125
+ return decorator
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
File without changes
File without changes
File without changes
File without changes
File without changes