jararaca 0.3.11a10__tar.gz → 0.3.11a12__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.

Potentially problematic release.


This version of jararaca might be problematic. Click here for more details.

Files changed (84) hide show
  1. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/PKG-INFO +1 -1
  2. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/docs/index.md +1 -17
  3. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/pyproject.toml +1 -1
  4. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/__init__.py +0 -3
  5. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/cli.py +23 -150
  6. jararaca-0.3.11a10/src/jararaca/scheduler/scheduler_v2.py → jararaca-0.3.11a12/src/jararaca/scheduler/beat_worker.py +12 -24
  7. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/utils/rabbitmq_utils.py +10 -56
  8. jararaca-0.3.11a10/src/jararaca/messagebus/worker.py +0 -423
  9. jararaca-0.3.11a10/src/jararaca/scheduler/scheduler.py +0 -181
  10. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/LICENSE +0 -0
  11. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/README.md +0 -0
  12. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/docs/CNAME +0 -0
  13. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/docs/architecture.md +0 -0
  14. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.jpeg +0 -0
  15. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.webp +0 -0
  16. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/docs/assets/tracing_example.png +0 -0
  17. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/docs/messagebus.md +0 -0
  18. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/docs/scheduler.md +0 -0
  19. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/docs/stylesheets/custom.css +0 -0
  20. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/docs/websocket.md +0 -0
  21. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/__main__.py +0 -0
  22. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/broker_backend/__init__.py +0 -0
  23. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/broker_backend/mapper.py +0 -0
  24. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/broker_backend/redis_broker_backend.py +0 -0
  25. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/common/__init__.py +0 -0
  26. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/core/__init__.py +0 -0
  27. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/core/providers.py +0 -0
  28. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/core/uow.py +0 -0
  29. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/di.py +0 -0
  30. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/files/entity.py.mako +0 -0
  31. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/lifecycle.py +0 -0
  32. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/messagebus/__init__.py +0 -0
  33. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/messagebus/bus_message_controller.py +0 -0
  34. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/messagebus/consumers/__init__.py +0 -0
  35. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/messagebus/decorators.py +0 -0
  36. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/messagebus/interceptors/__init__.py +0 -0
  37. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/messagebus/interceptors/aiopika_publisher_interceptor.py +0 -0
  38. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/messagebus/interceptors/publisher_interceptor.py +0 -0
  39. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/messagebus/message.py +0 -0
  40. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/messagebus/publisher.py +0 -0
  41. /jararaca-0.3.11a10/src/jararaca/messagebus/worker_v2.py → /jararaca-0.3.11a12/src/jararaca/messagebus/worker.py +0 -0
  42. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/microservice.py +0 -0
  43. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/observability/decorators.py +0 -0
  44. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/observability/interceptor.py +0 -0
  45. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/observability/providers/__init__.py +0 -0
  46. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/observability/providers/otel.py +0 -0
  47. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/persistence/base.py +0 -0
  48. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/persistence/exports.py +0 -0
  49. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/persistence/interceptors/__init__.py +0 -0
  50. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/persistence/interceptors/aiosqa_interceptor.py +0 -0
  51. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/persistence/session.py +0 -0
  52. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/persistence/sort_filter.py +0 -0
  53. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/persistence/utilities.py +0 -0
  54. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/presentation/__init__.py +0 -0
  55. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/presentation/decorators.py +0 -0
  56. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/presentation/hooks.py +0 -0
  57. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/presentation/http_microservice.py +0 -0
  58. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/presentation/server.py +0 -0
  59. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/presentation/websocket/__init__.py +0 -0
  60. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/presentation/websocket/base_types.py +0 -0
  61. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/presentation/websocket/context.py +0 -0
  62. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/presentation/websocket/decorators.py +0 -0
  63. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/presentation/websocket/redis.py +0 -0
  64. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/presentation/websocket/types.py +0 -0
  65. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/presentation/websocket/websocket_interceptor.py +0 -0
  66. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/py.typed +0 -0
  67. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/reflect/__init__.py +0 -0
  68. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/reflect/controller_inspect.py +0 -0
  69. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/reflect/metadata.py +0 -0
  70. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/rpc/__init__.py +0 -0
  71. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/rpc/http/__init__.py +0 -0
  72. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/rpc/http/backends/__init__.py +0 -0
  73. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/rpc/http/backends/httpx.py +0 -0
  74. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/rpc/http/backends/otel.py +0 -0
  75. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/rpc/http/decorators.py +0 -0
  76. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/rpc/http/httpx.py +0 -0
  77. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/scheduler/__init__.py +0 -0
  78. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/scheduler/decorators.py +0 -0
  79. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/scheduler/types.py +0 -0
  80. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/tools/app_config/__init__.py +0 -0
  81. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/tools/app_config/decorators.py +0 -0
  82. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/tools/app_config/interceptor.py +0 -0
  83. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/tools/typescript/interface_parser.py +0 -0
  84. {jararaca-0.3.11a10 → jararaca-0.3.11a12}/src/jararaca/utils/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: jararaca
3
- Version: 0.3.11a10
3
+ Version: 0.3.11a12
4
4
  Summary: A simple and fast API framework for Python
5
5
  Author: Lucas S
6
6
  Author-email: me@luscasleo.dev
@@ -33,25 +33,9 @@ Starts a message bus worker that processes asynchronous messages from a message
33
33
 
34
34
  **Options:**
35
35
 
36
- - `--url`: AMQP URL (default: "amqp://guest:guest@localhost/")
37
- - `--username`: AMQP username (optional)
38
- - `--password`: AMQP password (optional)
39
- - `--exchange`: Exchange name (default: "jararaca_ex")
40
- - `--queue`: Queue name (default: "jararaca_q")
41
- - `--prefetch-count`: Number of messages to prefetch (default: 1)
42
-
43
- ### `worker_v2` - Enhanced Message Bus Worker
44
-
45
- ```bash
46
- jararaca worker_v2 APP_PATH [OPTIONS]
47
- ```
48
-
49
- Starts an enhanced version of the message bus worker with improved backend support.
50
-
51
- **Options:**
52
-
53
36
  - `--broker-url`: The URL for the message broker (required)
54
37
  - `--backend-url`: The URL for the message broker backend (required)
38
+ - `--handlers`: Comma-separated list of handler names to listen to (optional)
55
39
 
56
40
  ### `server` - HTTP Server
57
41
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "jararaca"
3
- version = "0.3.11a10"
3
+ version = "0.3.11a12"
4
4
  description = "A simple and fast API framework for Python"
5
5
  authors = ["Lucas S <me@luscasleo.dev>"]
6
6
  readme = "README.md"
@@ -79,7 +79,6 @@ if TYPE_CHECKING:
79
79
  )
80
80
  from .messagebus.message import Message, MessageOf
81
81
  from .messagebus.publisher import use_publisher
82
- from .messagebus.worker import MessageBusWorker
83
82
  from .microservice import (
84
83
  Microservice,
85
84
  use_app_context,
@@ -215,7 +214,6 @@ if TYPE_CHECKING:
215
214
  "AIOSqlAlchemySessionInterceptor",
216
215
  "AIOSQAConfig",
217
216
  "create_http_server",
218
- "MessageBusWorker",
219
217
  "Container",
220
218
  "WebSocketInterceptor",
221
219
  "use_session",
@@ -367,7 +365,6 @@ _dynamic_imports: "dict[str, tuple[str, str, str | None]]" = {
367
365
  None,
368
366
  ),
369
367
  "create_http_server": (__SPEC_PARENT__, "presentation.server", None),
370
- "MessageBusWorker": (__SPEC_PARENT__, "messagebus.worker", None),
371
368
  "Container": (__SPEC_PARENT__, "di", None),
372
369
  "WebSocketInterceptor": (
373
370
  __SPEC_PARENT__,
@@ -8,23 +8,21 @@ import time
8
8
  from codecs import StreamWriter
9
9
  from pathlib import Path
10
10
  from typing import Any
11
- from urllib.parse import parse_qs, urlparse, urlunsplit
11
+ from urllib.parse import parse_qs, urlparse
12
12
 
13
13
  import aio_pika
14
14
  import click
15
15
  import uvicorn
16
16
  from mako.template import Template
17
17
 
18
- from jararaca.messagebus import worker as worker_v1
19
- from jararaca.messagebus import worker_v2 as worker_v2_mod
18
+ from jararaca.messagebus import worker as worker_mod
20
19
  from jararaca.messagebus.decorators import MessageBusController, MessageHandler
21
20
  from jararaca.microservice import Microservice
22
21
  from jararaca.presentation.http_microservice import HttpMicroservice
23
22
  from jararaca.presentation.server import create_http_server
24
23
  from jararaca.reflect.controller_inspect import inspect_controller
24
+ from jararaca.scheduler.beat_worker import BeatWorker
25
25
  from jararaca.scheduler.decorators import ScheduledAction
26
- from jararaca.scheduler.scheduler import Scheduler
27
- from jararaca.scheduler.scheduler_v2 import SchedulerV2
28
26
  from jararaca.tools.typescript.interface_parser import (
29
27
  write_microservice_to_typescript_interface,
30
28
  )
@@ -144,7 +142,7 @@ async def declare_worker_infrastructure(
144
142
  await RabbitmqUtils.delete_queue(channel, queue_name)
145
143
 
146
144
  # Declare queue
147
- queue = await RabbitmqUtils.declare_queue(
145
+ queue = await RabbitmqUtils.declare_worker_queue(
148
146
  channel=channel, queue_name=queue_name, passive=not force
149
147
  )
150
148
  await queue.bind(exchange=exchange, routing_key=routing_key)
@@ -166,7 +164,7 @@ async def declare_worker_infrastructure(
166
164
  if force:
167
165
  await RabbitmqUtils.delete_queue(channel, queue_name)
168
166
 
169
- queue = await RabbitmqUtils.declare_queue(
167
+ queue = await RabbitmqUtils.declare_scheduled_action_queue(
170
168
  channel=channel, queue_name=queue_name, passive=not force
171
169
  )
172
170
  await queue.bind(exchange=exchange, routing_key=routing_key)
@@ -183,98 +181,6 @@ def cli() -> None:
183
181
  pass
184
182
 
185
183
 
186
- @cli.command()
187
- @click.argument(
188
- "app_path",
189
- type=str,
190
- )
191
- @click.option(
192
- "--url",
193
- type=str,
194
- envvar="BROKER_URL",
195
- )
196
- @click.option(
197
- "--username",
198
- type=str,
199
- default=None,
200
- )
201
- @click.option(
202
- "--password",
203
- type=str,
204
- default=None,
205
- )
206
- @click.option(
207
- "--exchange",
208
- type=str,
209
- default="jararaca_ex",
210
- )
211
- @click.option(
212
- "--prefetch-count",
213
- type=int,
214
- default=1,
215
- )
216
- @click.option(
217
- "--passive-declare",
218
- is_flag=True,
219
- default=False,
220
- help="[DEPRECATED] Use passive declarations (check if infrastructure exists without creating it)",
221
- )
222
- @click.option(
223
- "--handlers",
224
- type=str,
225
- help="Comma-separated list of handler names to listen to. If not specified, all handlers will be used.",
226
- )
227
- def worker(
228
- app_path: str,
229
- url: str,
230
- username: str | None,
231
- password: str | None,
232
- exchange: str,
233
- prefetch_count: int,
234
- handlers: str | None,
235
- passive_declare: bool,
236
- ) -> None:
237
-
238
- app = find_microservice_by_module_path(app_path)
239
-
240
- parsed_url = urlparse(url)
241
-
242
- if password is not None:
243
- parsed_url = urlparse(
244
- urlunsplit(
245
- parsed_url._replace(
246
- netloc=f"{parsed_url.username or ''}:{password}@{parsed_url.netloc}"
247
- )
248
- )
249
- )
250
-
251
- if username is not None:
252
- parsed_url = urlparse(
253
- urlunsplit(
254
- parsed_url._replace(
255
- netloc=f"{username}{':%s' % password if password is not None else ''}@{parsed_url.netloc}"
256
- )
257
- )
258
- )
259
-
260
- url = parsed_url.geturl()
261
-
262
- # Parse handler names if provided
263
- handler_names: set[str] | None = None
264
- if handlers:
265
- handler_names = {name.strip() for name in handlers.split(",") if name.strip()}
266
-
267
- config = worker_v1.AioPikaWorkerConfig(
268
- url=url,
269
- exchange=exchange,
270
- prefetch_count=prefetch_count,
271
- )
272
-
273
- worker_v1.MessageBusWorker(app, config=config).start_sync(
274
- handler_names=handler_names,
275
- )
276
-
277
-
278
184
  @cli.command()
279
185
  @click.argument(
280
186
  "app_path",
@@ -285,21 +191,25 @@ def worker(
285
191
  "--broker-url",
286
192
  type=str,
287
193
  envvar="BROKER_URL",
194
+ required=True,
195
+ help="The URL for the message broker",
288
196
  )
289
197
  @click.option(
290
198
  "--backend-url",
291
199
  type=str,
292
200
  envvar="BACKEND_URL",
201
+ required=True,
202
+ help="The URL for the message broker backend",
293
203
  )
294
204
  @click.option(
295
205
  "--handlers",
296
206
  type=str,
297
207
  help="Comma-separated list of handler names to listen to. If not specified, all handlers will be used.",
298
208
  )
299
- def worker_v2(
209
+ def worker(
300
210
  app_path: str, broker_url: str, backend_url: str, handlers: str | None
301
211
  ) -> None:
302
-
212
+ """Start a message bus worker that processes asynchronous messages from a message queue."""
303
213
  app = find_microservice_by_module_path(app_path)
304
214
 
305
215
  # Parse handler names if provided
@@ -307,7 +217,7 @@ def worker_v2(
307
217
  if handlers:
308
218
  handler_names = {name.strip() for name in handlers.split(",") if name.strip()}
309
219
 
310
- worker_v2_mod.MessageBusWorker(
220
+ worker_mod.MessageBusWorker(
311
221
  app=app,
312
222
  broker_url=broker_url,
313
223
  backend_url=backend_url,
@@ -354,38 +264,6 @@ def server(app_path: str, host: str, port: int) -> None:
354
264
  uvicorn.run(asgi_app, host=host, port=port)
355
265
 
356
266
 
357
- @cli.command()
358
- @click.argument(
359
- "app_path",
360
- type=str,
361
- )
362
- @click.option(
363
- "--interval",
364
- type=int,
365
- default=1,
366
- )
367
- @click.option(
368
- "--schedulers",
369
- type=str,
370
- help="Comma-separated list of scheduler names to run (only run schedulers with these names)",
371
- )
372
- def scheduler(
373
- app_path: str,
374
- interval: int,
375
- schedulers: str | None = None,
376
- ) -> None:
377
- app = find_microservice_by_module_path(app_path)
378
-
379
- # Parse scheduler names if provided
380
- scheduler_names: set[str] | None = None
381
- if schedulers:
382
- scheduler_names = {
383
- name.strip() for name in schedulers.split(",") if name.strip()
384
- }
385
-
386
- Scheduler(app, interval=interval, scheduler_names=scheduler_names).run()
387
-
388
-
389
267
  @cli.command()
390
268
  @click.argument(
391
269
  "app_path",
@@ -408,35 +286,33 @@ def scheduler(
408
286
  required=True,
409
287
  )
410
288
  @click.option(
411
- "--schedulers",
289
+ "--actions",
412
290
  type=str,
413
- help="Comma-separated list of scheduler names to run (only run schedulers with these names)",
291
+ help="Comma-separated list of action names to run (only run actions with these names)",
414
292
  )
415
- def scheduler_v2(
293
+ def beat(
416
294
  interval: int,
417
295
  broker_url: str,
418
296
  backend_url: str,
419
297
  app_path: str,
420
- schedulers: str | None = None,
298
+ actions: str | None = None,
421
299
  ) -> None:
422
300
 
423
301
  app = find_microservice_by_module_path(app_path)
424
302
 
425
303
  # Parse scheduler names if provided
426
304
  scheduler_names: set[str] | None = None
427
- if schedulers:
428
- scheduler_names = {
429
- name.strip() for name in schedulers.split(",") if name.strip()
430
- }
305
+ if actions:
306
+ scheduler_names = {name.strip() for name in actions.split(",") if name.strip()}
431
307
 
432
- scheduler = SchedulerV2(
308
+ beat_worker = BeatWorker(
433
309
  app=app,
434
310
  interval=interval,
435
311
  backend_url=backend_url,
436
312
  broker_url=broker_url,
437
- scheduler_names=scheduler_names,
313
+ scheduled_action_names=scheduler_names,
438
314
  )
439
- scheduler.run()
315
+ beat_worker.run()
440
316
 
441
317
 
442
318
  def generate_interfaces(
@@ -663,6 +539,7 @@ def gen_entity(entity_name: str, file_path: StreamWriter) -> None:
663
539
  @click.argument(
664
540
  "app_path",
665
541
  type=str,
542
+ envvar="APP_PATH",
666
543
  )
667
544
  @click.option(
668
545
  "--broker-url",
@@ -766,13 +643,9 @@ def declare(
766
643
  click.echo(
767
644
  f"→ Declaring worker infrastructure (URL: {broker_url_with_exchange})"
768
645
  )
769
- click.echo(
770
- f"→ Declaring scheduler infrastructure (URL: {broker_url_with_exchange})"
771
- )
772
-
773
646
  await declare_worker_infrastructure(broker_url_with_exchange, app, force)
774
647
 
775
- click.echo("✓ Worker and scheduler infrastructure declared successfully!")
648
+ click.echo("✓ Workers infrastructure declared successfully!")
776
649
  except Exception as e:
777
650
  click.echo(f"ERROR: Failed to declare infrastructure: {e}", err=True)
778
651
  raise
@@ -4,10 +4,9 @@ import logging
4
4
  import signal
5
5
  import time
6
6
  from abc import ABC, abstractmethod
7
- from contextlib import asynccontextmanager
8
7
  from datetime import UTC, datetime
9
8
  from types import FrameType
10
- from typing import Any, AsyncGenerator
9
+ from typing import Any
11
10
  from urllib.parse import parse_qs
12
11
 
13
12
  import aio_pika
@@ -36,7 +35,7 @@ from jararaca.utils.rabbitmq_utils import RabbitmqUtils
36
35
  logger = logging.getLogger(__name__)
37
36
 
38
37
 
39
- def extract_scheduled_actions(
38
+ def _extract_scheduled_actions(
40
39
  app: Microservice, container: Container, scheduler_names: set[str] | None = None
41
40
  ) -> list[ScheduledActionData]:
42
41
  scheduled_actions: list[ScheduledActionData] = []
@@ -64,7 +63,7 @@ def extract_scheduled_actions(
64
63
  # region Message Broker Dispatcher
65
64
 
66
65
 
67
- class MessageBrokerDispatcher(ABC):
66
+ class _MessageBrokerDispatcher(ABC):
68
67
 
69
68
  @abstractmethod
70
69
  async def dispatch_scheduled_action(
@@ -100,7 +99,7 @@ class MessageBrokerDispatcher(ABC):
100
99
  pass
101
100
 
102
101
 
103
- class RabbitMQBrokerDispatcher(MessageBrokerDispatcher):
102
+ class _RabbitMQBrokerDispatcher(_MessageBrokerDispatcher):
104
103
 
105
104
  def __init__(self, url: str) -> None:
106
105
  self.url = url
@@ -196,7 +195,7 @@ class RabbitMQBrokerDispatcher(MessageBrokerDispatcher):
196
195
  queue_name = ScheduledAction.get_function_id(sched_act_data.callable)
197
196
 
198
197
  # Try to get existing queue
199
- await RabbitmqUtils.get_scheduler_queue(
198
+ await RabbitmqUtils.get_scheduled_action_queue(
200
199
  channel=channel,
201
200
  queue_name=queue_name,
202
201
  )
@@ -206,13 +205,13 @@ class RabbitMQBrokerDispatcher(MessageBrokerDispatcher):
206
205
  await self.conn_pool.close()
207
206
 
208
207
 
209
- def get_message_broker_dispatcher_from_url(url: str) -> MessageBrokerDispatcher:
208
+ def _get_message_broker_dispatcher_from_url(url: str) -> _MessageBrokerDispatcher:
210
209
  """
211
210
  Factory function to create a message broker instance from a URL.
212
211
  Currently, only RabbitMQ is supported.
213
212
  """
214
213
  if url.startswith("amqp://") or url.startswith("amqps://"):
215
- return RabbitMQBrokerDispatcher(url=url)
214
+ return _RabbitMQBrokerDispatcher(url=url)
216
215
  else:
217
216
  raise ValueError(f"Unsupported message broker URL: {url}")
218
217
 
@@ -220,7 +219,7 @@ def get_message_broker_dispatcher_from_url(url: str) -> MessageBrokerDispatcher:
220
219
  # endregion
221
220
 
222
221
 
223
- class SchedulerV2:
222
+ class BeatWorker:
224
223
 
225
224
  def __init__(
226
225
  self,
@@ -228,11 +227,11 @@ class SchedulerV2:
228
227
  interval: int,
229
228
  broker_url: str,
230
229
  backend_url: str,
231
- scheduler_names: set[str] | None = None,
230
+ scheduled_action_names: set[str] | None = None,
232
231
  ) -> None:
233
232
  self.app = app
234
233
 
235
- self.broker: MessageBrokerDispatcher = get_message_broker_dispatcher_from_url(
234
+ self.broker: _MessageBrokerDispatcher = _get_message_broker_dispatcher_from_url(
236
235
  broker_url
237
236
  )
238
237
  self.backend: MessageBrokerBackend = get_message_broker_backend_from_url(
@@ -240,7 +239,7 @@ class SchedulerV2:
240
239
  )
241
240
 
242
241
  self.interval = interval
243
- self.scheduler_names = scheduler_names
242
+ self.scheduler_names = scheduled_action_names
244
243
  self.container = Container(self.app)
245
244
  self.uow_provider = UnitOfWorkContextProvider(app, self.container)
246
245
 
@@ -266,7 +265,7 @@ class SchedulerV2:
266
265
  """
267
266
  async with self.lifecycle():
268
267
 
269
- scheduled_actions = extract_scheduled_actions(
268
+ scheduled_actions = _extract_scheduled_actions(
270
269
  self.app, self.container, self.scheduler_names
271
270
  )
272
271
 
@@ -341,14 +340,3 @@ class SchedulerV2:
341
340
 
342
341
  await self.backend.dispose()
343
342
  await self.broker.dispose()
344
-
345
-
346
- @asynccontextmanager
347
- async def none_context() -> AsyncGenerator[None, None]:
348
- yield
349
-
350
-
351
- logging.basicConfig(
352
- level=logging.INFO,
353
- format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
354
- )
@@ -222,7 +222,7 @@ class RabbitmqUtils:
222
222
  raise
223
223
 
224
224
  @classmethod
225
- async def declare_queue(
225
+ async def declare_worker_queue(
226
226
  cls,
227
227
  channel: AbstractChannel,
228
228
  queue_name: str,
@@ -243,64 +243,13 @@ class RabbitmqUtils:
243
243
  )
244
244
 
245
245
  @classmethod
246
- async def get_worker_v1_queue(
246
+ async def get_scheduled_action_queue(
247
247
  cls,
248
248
  channel: AbstractChannel,
249
249
  queue_name: str,
250
250
  ) -> AbstractQueue:
251
251
  """
252
- Get a worker v1 queue.
253
- """
254
- try:
255
- return await channel.get_queue(queue_name)
256
- except ChannelNotFoundEntity as e:
257
- logger.error(
258
- f"Worker queue '{queue_name}' does not exist. "
259
- f"Please use the declare command to create it first. Error: {e}"
260
- )
261
- raise
262
- except ChannelClosed as e:
263
- logger.error(
264
- f"Channel closed while getting worker queue '{queue_name}'. "
265
- f"Error: {e}"
266
- )
267
- raise
268
- except AMQPError as e:
269
- logger.error(
270
- f"AMQP error while getting worker queue '{queue_name}'. " f"Error: {e}"
271
- )
272
- raise
273
-
274
- @classmethod
275
- async def declare_worker_v1_queue(
276
- cls,
277
- channel: AbstractChannel,
278
- queue_name: str,
279
- dlx_name: str,
280
- dlq_name: str,
281
- passive: bool = False,
282
- ) -> AbstractQueue:
283
- """
284
- Declare a worker v1 queue with custom dead letter exchange and routing key.
285
- """
286
- return await channel.declare_queue(
287
- passive=passive,
288
- name=queue_name,
289
- arguments={
290
- "x-dead-letter-exchange": dlx_name,
291
- "x-dead-letter-routing-key": dlq_name,
292
- },
293
- durable=True,
294
- )
295
-
296
- @classmethod
297
- async def get_scheduler_queue(
298
- cls,
299
- channel: AbstractChannel,
300
- queue_name: str,
301
- ) -> AbstractQueue:
302
- """
303
- Get a scheduler queue.
252
+ Get a scheduled action queue.
304
253
  """
305
254
  try:
306
255
  return await channel.get_queue(queue_name)
@@ -324,19 +273,24 @@ class RabbitmqUtils:
324
273
  raise
325
274
 
326
275
  @classmethod
327
- async def declare_scheduler_queue(
276
+ async def declare_scheduled_action_queue(
328
277
  cls,
329
278
  channel: AbstractChannel,
330
279
  queue_name: str,
331
280
  passive: bool = False,
332
281
  ) -> AbstractQueue:
333
282
  """
334
- Declare a scheduler queue with simple durable configuration.
283
+ Declare a scheduled action queue with simple durable configuration.
284
+ The queue has a max length of 1 to ensure only one scheduled task
285
+ is processed at a time.
335
286
  """
336
287
  return await channel.declare_queue(
337
288
  name=queue_name,
338
289
  durable=True,
339
290
  passive=passive,
291
+ arguments={
292
+ "x-max-length": 1,
293
+ },
340
294
  )
341
295
 
342
296
  @classmethod