jararaca 0.3.11a9__tar.gz → 0.3.11a11__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.
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/PKG-INFO +1 -1
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/docs/index.md +1 -17
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/pyproject.toml +1 -1
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/__init__.py +3 -3
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/cli.py +19 -143
- jararaca-0.3.11a9/src/jararaca/scheduler/scheduler_v2.py → jararaca-0.3.11a11/src/jararaca/scheduler/beat_worker.py +11 -23
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/utils/rabbitmq_utils.py +5 -0
- jararaca-0.3.11a9/src/jararaca/messagebus/worker.py +0 -423
- jararaca-0.3.11a9/src/jararaca/scheduler/scheduler.py +0 -181
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/LICENSE +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/README.md +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/docs/CNAME +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/docs/architecture.md +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.jpeg +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.webp +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/docs/assets/tracing_example.png +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/docs/messagebus.md +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/docs/scheduler.md +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/docs/stylesheets/custom.css +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/docs/websocket.md +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/__main__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/broker_backend/__init__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/broker_backend/mapper.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/broker_backend/redis_broker_backend.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/common/__init__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/core/__init__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/core/providers.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/core/uow.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/di.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/files/entity.py.mako +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/lifecycle.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/messagebus/__init__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/messagebus/bus_message_controller.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/messagebus/consumers/__init__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/messagebus/decorators.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/messagebus/interceptors/__init__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/messagebus/interceptors/aiopika_publisher_interceptor.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/messagebus/interceptors/publisher_interceptor.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/messagebus/message.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/messagebus/publisher.py +0 -0
- /jararaca-0.3.11a9/src/jararaca/messagebus/worker_v2.py → /jararaca-0.3.11a11/src/jararaca/messagebus/worker.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/microservice.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/observability/decorators.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/observability/interceptor.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/observability/providers/__init__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/observability/providers/otel.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/persistence/base.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/persistence/exports.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/persistence/interceptors/__init__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/persistence/interceptors/aiosqa_interceptor.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/persistence/session.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/persistence/sort_filter.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/persistence/utilities.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/presentation/__init__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/presentation/decorators.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/presentation/hooks.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/presentation/http_microservice.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/presentation/server.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/presentation/websocket/__init__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/presentation/websocket/base_types.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/presentation/websocket/context.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/presentation/websocket/decorators.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/presentation/websocket/redis.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/presentation/websocket/types.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/presentation/websocket/websocket_interceptor.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/py.typed +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/reflect/__init__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/reflect/controller_inspect.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/reflect/metadata.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/rpc/__init__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/rpc/http/__init__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/rpc/http/backends/__init__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/rpc/http/backends/httpx.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/rpc/http/backends/otel.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/rpc/http/decorators.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/rpc/http/httpx.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/scheduler/__init__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/scheduler/decorators.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/scheduler/types.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/tools/app_config/__init__.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/tools/app_config/decorators.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/tools/app_config/interceptor.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/tools/typescript/interface_parser.py +0 -0
- {jararaca-0.3.11a9 → jararaca-0.3.11a11}/src/jararaca/utils/__init__.py +0 -0
|
@@ -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
|
|
|
@@ -64,6 +64,7 @@ if TYPE_CHECKING:
|
|
|
64
64
|
RestClient,
|
|
65
65
|
RouteHttpErrorHandler,
|
|
66
66
|
RPCRequestNetworkError,
|
|
67
|
+
RPCUnhandleError,
|
|
67
68
|
)
|
|
68
69
|
|
|
69
70
|
from .core.providers import ProviderSpec, Token
|
|
@@ -78,7 +79,6 @@ if TYPE_CHECKING:
|
|
|
78
79
|
)
|
|
79
80
|
from .messagebus.message import Message, MessageOf
|
|
80
81
|
from .messagebus.publisher import use_publisher
|
|
81
|
-
from .messagebus.worker import MessageBusWorker
|
|
82
82
|
from .microservice import (
|
|
83
83
|
Microservice,
|
|
84
84
|
use_app_context,
|
|
@@ -154,6 +154,7 @@ if TYPE_CHECKING:
|
|
|
154
154
|
"retry",
|
|
155
155
|
"retry_later",
|
|
156
156
|
"RPCRequestNetworkError",
|
|
157
|
+
"RPCUnhandleError",
|
|
157
158
|
"FILTER_SORT_ENTITY_ATTR_MAP",
|
|
158
159
|
"FilterModel",
|
|
159
160
|
"SortFilterRunner",
|
|
@@ -213,7 +214,6 @@ if TYPE_CHECKING:
|
|
|
213
214
|
"AIOSqlAlchemySessionInterceptor",
|
|
214
215
|
"AIOSQAConfig",
|
|
215
216
|
"create_http_server",
|
|
216
|
-
"MessageBusWorker",
|
|
217
217
|
"Container",
|
|
218
218
|
"WebSocketInterceptor",
|
|
219
219
|
"use_session",
|
|
@@ -284,6 +284,7 @@ _dynamic_imports: "dict[str, tuple[str, str, str | None]]" = {
|
|
|
284
284
|
"retry": (__SPEC_PARENT__, "messagebus.bus_message_controller", None),
|
|
285
285
|
"retry_later": (__SPEC_PARENT__, "messagebus.bus_message_controller", None),
|
|
286
286
|
"RPCRequestNetworkError": (__SPEC_PARENT__, "rpc.http.decorators", None),
|
|
287
|
+
"RPCUnhandleError": (__SPEC_PARENT__, "rpc.http.decorators", None),
|
|
287
288
|
"FILTER_SORT_ENTITY_ATTR_MAP": (__SPEC_PARENT__, "persistence.sort_filter", None),
|
|
288
289
|
"FilterModel": (__SPEC_PARENT__, "persistence.sort_filter", None),
|
|
289
290
|
"SortFilterRunner": (__SPEC_PARENT__, "persistence.sort_filter", None),
|
|
@@ -364,7 +365,6 @@ _dynamic_imports: "dict[str, tuple[str, str, str | None]]" = {
|
|
|
364
365
|
None,
|
|
365
366
|
),
|
|
366
367
|
"create_http_server": (__SPEC_PARENT__, "presentation.server", None),
|
|
367
|
-
"MessageBusWorker": (__SPEC_PARENT__, "messagebus.worker", None),
|
|
368
368
|
"Container": (__SPEC_PARENT__, "di", None),
|
|
369
369
|
"WebSocketInterceptor": (
|
|
370
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
|
|
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
|
|
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
|
)
|
|
@@ -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
|
|
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
|
-
|
|
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
|
-
"--
|
|
289
|
+
"--actions",
|
|
412
290
|
type=str,
|
|
413
|
-
help="Comma-separated list of
|
|
291
|
+
help="Comma-separated list of action names to run (only run actions with these names)",
|
|
414
292
|
)
|
|
415
|
-
def
|
|
293
|
+
def beat(
|
|
416
294
|
interval: int,
|
|
417
295
|
broker_url: str,
|
|
418
296
|
backend_url: str,
|
|
419
297
|
app_path: str,
|
|
420
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
313
|
+
scheduled_action_names=scheduler_names,
|
|
438
314
|
)
|
|
439
|
-
|
|
315
|
+
beat_worker.run()
|
|
440
316
|
|
|
441
317
|
|
|
442
318
|
def generate_interfaces(
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
102
|
+
class _RabbitMQBrokerDispatcher(_MessageBrokerDispatcher):
|
|
104
103
|
|
|
105
104
|
def __init__(self, url: str) -> None:
|
|
106
105
|
self.url = url
|
|
@@ -206,13 +205,13 @@ class RabbitMQBrokerDispatcher(MessageBrokerDispatcher):
|
|
|
206
205
|
await self.conn_pool.close()
|
|
207
206
|
|
|
208
207
|
|
|
209
|
-
def
|
|
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
|
|
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
|
|
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
|
-
|
|
230
|
+
scheduled_action_names: set[str] | None = None,
|
|
232
231
|
) -> None:
|
|
233
232
|
self.app = app
|
|
234
233
|
|
|
235
|
-
self.broker:
|
|
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 =
|
|
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 =
|
|
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
|
-
)
|
|
@@ -332,11 +332,16 @@ class RabbitmqUtils:
|
|
|
332
332
|
) -> AbstractQueue:
|
|
333
333
|
"""
|
|
334
334
|
Declare a scheduler queue with simple durable configuration.
|
|
335
|
+
The queue has a max length of 1 to ensure only one scheduled task
|
|
336
|
+
is processed at a time.
|
|
335
337
|
"""
|
|
336
338
|
return await channel.declare_queue(
|
|
337
339
|
name=queue_name,
|
|
338
340
|
durable=True,
|
|
339
341
|
passive=passive,
|
|
342
|
+
arguments={
|
|
343
|
+
"x-max-length": 1,
|
|
344
|
+
},
|
|
340
345
|
)
|
|
341
346
|
|
|
342
347
|
@classmethod
|