jararaca 0.3.11a15__tar.gz → 0.3.12a0__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 (85) hide show
  1. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/PKG-INFO +3 -3
  2. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/docs/index.md +143 -20
  3. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/docs/messagebus.md +26 -6
  4. jararaca-0.3.12a0/docs/retry.md +79 -0
  5. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/docs/scheduler.md +44 -24
  6. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/docs/websocket.md +24 -10
  7. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/pyproject.toml +1 -1
  8. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/cli.py +214 -31
  9. jararaca-0.3.12a0/src/jararaca/messagebus/worker.py +1416 -0
  10. jararaca-0.3.12a0/src/jararaca/utils/retry.py +141 -0
  11. jararaca-0.3.11a15/src/jararaca/messagebus/worker.py +0 -644
  12. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/LICENSE +0 -0
  13. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/README.md +0 -0
  14. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/docs/CNAME +0 -0
  15. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/docs/architecture.md +0 -0
  16. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.jpeg +0 -0
  17. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.webp +0 -0
  18. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/docs/assets/tracing_example.png +0 -0
  19. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/docs/stylesheets/custom.css +0 -0
  20. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/__init__.py +0 -0
  21. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/__main__.py +0 -0
  22. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/broker_backend/__init__.py +0 -0
  23. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/broker_backend/mapper.py +0 -0
  24. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/broker_backend/redis_broker_backend.py +0 -0
  25. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/common/__init__.py +0 -0
  26. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/core/__init__.py +0 -0
  27. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/core/providers.py +0 -0
  28. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/core/uow.py +0 -0
  29. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/di.py +0 -0
  30. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/files/entity.py.mako +0 -0
  31. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/lifecycle.py +0 -0
  32. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/messagebus/__init__.py +0 -0
  33. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/messagebus/bus_message_controller.py +0 -0
  34. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/messagebus/consumers/__init__.py +0 -0
  35. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/messagebus/decorators.py +0 -0
  36. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/messagebus/interceptors/__init__.py +0 -0
  37. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/messagebus/interceptors/aiopika_publisher_interceptor.py +0 -0
  38. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/messagebus/interceptors/publisher_interceptor.py +0 -0
  39. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/messagebus/message.py +0 -0
  40. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/messagebus/publisher.py +0 -0
  41. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/microservice.py +0 -0
  42. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/observability/decorators.py +0 -0
  43. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/observability/interceptor.py +0 -0
  44. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/observability/providers/__init__.py +0 -0
  45. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/observability/providers/otel.py +0 -0
  46. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/persistence/base.py +0 -0
  47. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/persistence/exports.py +0 -0
  48. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/persistence/interceptors/__init__.py +0 -0
  49. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/persistence/interceptors/aiosqa_interceptor.py +0 -0
  50. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/persistence/session.py +0 -0
  51. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/persistence/sort_filter.py +0 -0
  52. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/persistence/utilities.py +0 -0
  53. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/presentation/__init__.py +0 -0
  54. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/presentation/decorators.py +0 -0
  55. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/presentation/hooks.py +0 -0
  56. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/presentation/http_microservice.py +0 -0
  57. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/presentation/server.py +0 -0
  58. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/presentation/websocket/__init__.py +0 -0
  59. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/presentation/websocket/base_types.py +0 -0
  60. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/presentation/websocket/context.py +0 -0
  61. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/presentation/websocket/decorators.py +0 -0
  62. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/presentation/websocket/redis.py +0 -0
  63. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/presentation/websocket/types.py +0 -0
  64. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/presentation/websocket/websocket_interceptor.py +0 -0
  65. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/py.typed +0 -0
  66. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/reflect/__init__.py +0 -0
  67. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/reflect/controller_inspect.py +0 -0
  68. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/reflect/metadata.py +0 -0
  69. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/rpc/__init__.py +0 -0
  70. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/rpc/http/__init__.py +0 -0
  71. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/rpc/http/backends/__init__.py +0 -0
  72. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/rpc/http/backends/httpx.py +0 -0
  73. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/rpc/http/backends/otel.py +0 -0
  74. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/rpc/http/decorators.py +0 -0
  75. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/rpc/http/httpx.py +0 -0
  76. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/scheduler/__init__.py +0 -0
  77. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/scheduler/beat_worker.py +0 -0
  78. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/scheduler/decorators.py +0 -0
  79. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/scheduler/types.py +0 -0
  80. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/tools/app_config/__init__.py +0 -0
  81. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/tools/app_config/decorators.py +0 -0
  82. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/tools/app_config/interceptor.py +0 -0
  83. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/tools/typescript/interface_parser.py +0 -0
  84. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/utils/__init__.py +0 -0
  85. {jararaca-0.3.11a15 → jararaca-0.3.12a0}/src/jararaca/utils/rabbitmq_utils.py +0 -0
@@ -1,14 +1,14 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.1
2
2
  Name: jararaca
3
- Version: 0.3.11a15
3
+ Version: 0.3.12a0
4
4
  Summary: A simple and fast API framework for Python
5
+ Home-page: https://github.com/LuscasLeo/jararaca
5
6
  Author: Lucas S
6
7
  Author-email: me@luscasleo.dev
7
8
  Requires-Python: >=3.11,<4.0
8
9
  Classifier: Programming Language :: Python :: 3
9
10
  Classifier: Programming Language :: Python :: 3.11
10
11
  Classifier: Programming Language :: Python :: 3.12
11
- Classifier: Programming Language :: Python :: 3.13
12
12
  Provides-Extra: docs
13
13
  Provides-Extra: http
14
14
  Provides-Extra: opentelemetry
@@ -9,9 +9,9 @@ Jararaca is a powerful Python microservice framework that provides a comprehensi
9
9
  - 📦 **Dependency Injection**: Flexible dependency injection system with interceptors
10
10
  - 📊 **Database Integration**: SQLAlchemy integration with async support
11
11
  - 📡 **Message Bus**: RabbitMQ integration for event-driven architecture
12
- - 🔒 **Authentication**: Built-in JWT authentication with token blacklisting
12
+ - **Retry Mechanism**: Robust retry system with exponential backoff for resilient operations
13
13
  - 🔍 **Query Operations**: Advanced query capabilities with pagination and filtering
14
- - ⏱️ **Scheduled Tasks**: Cron-based task scheduling
14
+ - ⏱️ **Scheduled Tasks**: Distributed cron-based task scheduling with message broker integration
15
15
 
16
16
  ## Installation
17
17
 
@@ -33,9 +33,27 @@ Starts a message bus worker that processes asynchronous messages from a message
33
33
 
34
34
  **Options:**
35
35
 
36
- - `--broker-url`: The URL for the message broker (required)
37
- - `--backend-url`: The URL for the message broker backend (required)
38
- - `--handlers`: Comma-separated list of handler names to listen to (optional)
36
+ - `--broker-url`: The URL for the message broker (required) [env: BROKER_URL]
37
+ - `--backend-url`: The URL for the message broker backend (required) [env: BACKEND_URL]
38
+ - `--handlers`: Comma-separated list of handler names to listen to (optional) [env: HANDLERS]
39
+ - `--reload`: Enable auto-reload when Python files change (for development) [env: RELOAD]
40
+ - `--src-dir`: The source directory to watch for changes when --reload is enabled (default: "src") [env: SRC_DIR]
41
+
42
+ **Environment Variables:**
43
+ - `APP_PATH`: The application module path
44
+ - All options support environment variables as indicated above
45
+
46
+ **Example with environment variables:**
47
+ ```bash
48
+ export APP_PATH="app.module:app"
49
+ export BROKER_URL="amqp://guest:guest@localhost:5672/?exchange=jararaca&prefetch_count=1"
50
+ export BACKEND_URL="redis://localhost:6379"
51
+ export HANDLERS="send_email,process_payment"
52
+ export RELOAD="true"
53
+ jararaca worker
54
+ ```
55
+ - `--reload`: Enable auto-reload when Python files change (for development)
56
+ - `--src-dir`: The source directory to watch for changes when --reload is enabled (default: "src")
39
57
 
40
58
  ### `server` - HTTP Server
41
59
 
@@ -43,11 +61,39 @@ Starts a message bus worker that processes asynchronous messages from a message
43
61
  jararaca server APP_PATH [OPTIONS]
44
62
  ```
45
63
 
46
- #### Perfer `uvicorn` for production
47
-
48
64
  Starts a FastAPI HTTP server for your microservice.
49
65
 
66
+ **Options:**
67
+
68
+ - `--host`: Host to bind the server (default: "0.0.0.0") [env: HOST]
69
+ - `--port`: Port to bind the server (default: 8000) [env: PORT]
70
+
71
+ **Environment Variables:**
72
+ - `APP_PATH`: The application module path
73
+ - `HOST`: Host to bind the server
74
+ - `PORT`: Port to bind the server
75
+
76
+ **Example with environment variables:**
77
+ ```bash
78
+ export APP_PATH="app.module:app"
79
+ export HOST="127.0.0.1"
80
+ export PORT="8080"
81
+ jararaca server
82
+ ```
83
+
84
+ #### Alternative: Using `uvicorn` directly
85
+
86
+ For production environments, you can create an ASGI application and run it with uvicorn:
87
+
50
88
  ```python
89
+ from fastapi import FastAPI
90
+ from fastapi.middleware.cors import CORSMiddleware
91
+ from fastapi.types import Lifespan
92
+
93
+ from jararaca.presentation.http_microservice import HttpMicroservice
94
+ from jararaca.presentation.server import create_http_server
95
+
96
+
51
97
  def fastapi_factory(lifespan: Lifespan[FastAPI]) -> FastAPI:
52
98
  app = FastAPI(
53
99
  lifespan=lifespan,
@@ -78,26 +124,37 @@ Then run the server with:
78
124
  uvicorn app_module:asgi_app
79
125
  ```
80
126
 
81
- Starts a FastAPI HTTP server for your microservice.
82
-
83
- **Options:**
84
-
85
- - `--host`: Host to bind the server (default: "0.0.0.0")
86
- - `--port`: Port to bind the server (default: 8000)
87
-
88
- ### `scheduler` - Task Scheduler
127
+ ### `beat` - Task Scheduler
89
128
 
90
129
  ```bash
91
- jararaca scheduler APP_PATH [OPTIONS]
130
+ jararaca beat APP_PATH [OPTIONS]
92
131
  ```
93
132
 
94
133
  Runs scheduled tasks defined in your application using cron expressions.
95
134
 
96
135
  **Options:**
97
136
 
98
- - `--interval`: Polling interval in seconds (default: 1)
137
+ - `--interval`: Polling interval in seconds (default: 1) [env: INTERVAL]
138
+ - `--broker-url`: The URL for the message broker (required) [env: BROKER_URL]
139
+ - `--backend-url`: The URL for the message broker backend (required) [env: BACKEND_URL]
140
+ - `--actions`: Comma-separated list of action names to run (optional) [env: ACTIONS]
141
+ - `--reload`: Enable auto-reload when Python files change (for development) [env: RELOAD]
142
+ - `--src-dir`: The source directory to watch for changes when --reload is enabled (default: "src") [env: SRC_DIR]
99
143
 
100
- ### `scheduler_v2` - Enhanced Task Scheduler
144
+ **Environment Variables:**
145
+ - `APP_PATH`: The application module path
146
+ - All options support environment variables as indicated above
147
+
148
+ **Example with environment variables:**
149
+ ```bash
150
+ export APP_PATH="app.module:app"
151
+ export INTERVAL="5"
152
+ export BROKER_URL="amqp://guest:guest@localhost:5672/?exchange=jararaca&prefetch_count=1"
153
+ export BACKEND_URL="redis://localhost:6379"
154
+ export ACTIONS="send_emails,process_payments"
155
+ export RELOAD="true"
156
+ jararaca beat
157
+ ```
101
158
 
102
159
  ```bash
103
160
  jararaca scheduler_v2 APP_PATH [OPTIONS]
@@ -121,8 +178,14 @@ Generates TypeScript interfaces from your Python models to ensure type safety be
121
178
 
122
179
  **Options:**
123
180
 
124
- - `--watch`: Watch for file changes and regenerate TypeScript interfaces automatically
125
- - `--src-dir`: Source directory to watch for changes (default: "src")
181
+ - `--watch`: Watch for file changes and regenerate TypeScript interfaces automatically [env: WATCH]
182
+ - `--src-dir`: Source directory to watch for changes (default: "src") [env: SRC_DIR]
183
+ - `--stdout`: Print generated interfaces to stdout instead of writing to a file [env: STDOUT]
184
+ - `--post-process`: Command to run after generating the interfaces, {file} will be replaced with the output file path [env: POST_PROCESS]
185
+
186
+ **Environment Variables:**
187
+ - `APP_PATH`: The application module path
188
+ - All options support environment variables as indicated above
126
189
 
127
190
  **Example with watch mode:**
128
191
 
@@ -132,6 +195,15 @@ jararaca gen-tsi app.module:app interfaces.ts --watch
132
195
 
133
196
  This will generate the TypeScript interfaces initially and then watch for any changes to Python files in the src directory, automatically regenerating the interfaces when changes are detected. You can stop watching with Ctrl+C.
134
197
 
198
+ **Example with environment variables:**
199
+ ```bash
200
+ export APP_PATH="app.module:app"
201
+ export FILE_PATH="interfaces.ts"
202
+ export WATCH="true"
203
+ export SRC_DIR="src"
204
+ jararaca gen-tsi
205
+ ```
206
+
135
207
  **Note:** To use the watch feature, you need to install the watchdog package:
136
208
 
137
209
  ```bash
@@ -152,6 +224,57 @@ jararaca gen-entity ENTITY_NAME FILE_PATH
152
224
 
153
225
  Generates a new entity file template with proper naming conventions in different formats (snake_case, PascalCase, kebab-case).
154
226
 
227
+ **Environment Variables:**
228
+ - `ENTITY_NAME`: The name of the entity to generate
229
+ - `FILE_PATH`: The path where the entity file should be created
230
+
231
+ **Example:**
232
+
233
+ ```bash
234
+ # Using command line arguments
235
+ jararaca gen-entity User user.py
236
+
237
+ # Using environment variables
238
+ export ENTITY_NAME="User"
239
+ export FILE_PATH="user.py"
240
+ jararaca gen-entity
241
+ ```
242
+
243
+ ### `declare` - Declare Message Infrastructure
244
+
245
+ ```bash
246
+ jararaca declare APP_PATH [OPTIONS]
247
+ ```
248
+
249
+ Declares RabbitMQ infrastructure (exchanges and queues) for message handlers and schedulers without starting the actual consumption processes.
250
+
251
+ **Options:**
252
+ - `--broker-url`: Broker URL (e.g., amqp://guest:guest@localhost/) [env: BROKER_URL]
253
+ - `-i, --interactive-mode`: Enable interactive mode for queue declaration [env: INTERACTIVE_MODE]
254
+ - `-f, --force`: Force recreation by deleting existing exchanges and queues [env: FORCE]
255
+
256
+ **Environment Variables:**
257
+ - `APP_PATH`: The application module path
258
+ - `BROKER_URL`: The broker URL
259
+ - `INTERACTIVE_MODE`: Enable interactive mode
260
+ - `FORCE`: Force recreation of infrastructure
261
+
262
+ **Examples:**
263
+
264
+ ```bash
265
+ # Declare infrastructure
266
+ jararaca declare myapp:app --broker-url amqp://guest:guest@localhost/
267
+
268
+ # Force recreation of queues and exchanges
269
+ jararaca declare myapp:app --broker-url amqp://guest:guest@localhost/ --force
270
+
271
+ # Using environment variables
272
+ export APP_PATH="myapp:app"
273
+ export BROKER_URL="amqp://guest:guest@localhost/"
274
+ export FORCE="true"
275
+ jararaca declare
276
+ ```
277
+
155
278
  ## Quick Start
156
279
 
157
280
  Here's a basic example of how to create a microservice with Jararaca:
@@ -29,6 +29,7 @@ graph TB
29
29
  ack[ack]
30
30
  nack[nack]
31
31
  retry[retry]
32
+ retry_later[retry_later]
32
33
  reject[reject]
33
34
  end
34
35
 
@@ -42,6 +43,7 @@ graph TB
42
43
  BusMessageController --> nack
43
44
  BusMessageController --> reject
44
45
  BusMessageController --> retry
46
+ BusMessageController --> retry_later
45
47
  ```
46
48
 
47
49
  ## Message Structure
@@ -453,12 +455,30 @@ jararaca worker APP_PATH [OPTIONS]
453
455
 
454
456
  Options:
455
457
 
456
- - `--url`: AMQP URL (default: "amqp://guest:guest@localhost/")
457
- - `--username`: AMQP username (optional)
458
- - `--password`: AMQP password (optional)
459
- - `--exchange`: Exchange name (default: "jararaca_ex")
460
- - `--queue`: Queue name (default: "jararaca_q")
461
- - `--prefetch-count`: Number of messages to prefetch (default: 1)
458
+ - `--broker-url`: The URL for the message broker (required) [env: BROKER_URL]
459
+ - `--backend-url`: The URL for the message broker backend (required) [env: BACKEND_URL]
460
+ - `--handlers`: Comma-separated list of handler names to listen to (optional) [env: HANDLERS]
461
+ - `--reload`: Enable auto-reload when Python files change (for development) [env: RELOAD]
462
+ - `--src-dir`: The source directory to watch for changes when --reload is enabled (default: "src") [env: SRC_DIR]
463
+
464
+ Examples:
465
+
466
+ ```bash
467
+ # Standard worker execution
468
+ jararaca worker myapp.main:app --broker-url "amqp://guest:guest@localhost:5672/?exchange=jararaca" --backend-url "redis://localhost:6379"
469
+
470
+ # With auto-reload for development
471
+ jararaca worker myapp.main:app --broker-url "amqp://guest:guest@localhost:5672/?exchange=jararaca" --backend-url "redis://localhost:6379" --reload
472
+
473
+ # Using environment variables
474
+ export APP_PATH="myapp.main:app"
475
+ export BROKER_URL="amqp://guest:guest@localhost:5672/?exchange=jararaca"
476
+ export BACKEND_URL="redis://localhost:6379"
477
+ export RELOAD="true"
478
+ export SRC_DIR="src"
479
+ export RELOAD="true"
480
+ jararaca worker
481
+ ```
462
482
 
463
483
  ## Conclusion
464
484
 
@@ -0,0 +1,79 @@
1
+ # Retry Mechanism with Exponential Backoff
2
+
3
+ Jararaca implements a robust retry mechanism with exponential backoff for handling transient failures in RabbitMQ connections and operations. This mechanism helps the system gracefully handle temporary network issues, broker unavailability, and other transient failures.
4
+
5
+ ## Core Components
6
+
7
+ The retry system consists of these main components:
8
+
9
+ 1. `RetryConfig` - Configuration class for customizing retry behavior
10
+ 2. `retry_with_backoff` - Utility function to execute operations with retry
11
+ 3. `with_retry` - Decorator for applying retry logic to functions
12
+
13
+ ## Retry Configuration
14
+
15
+ The `RetryConfig` class allows customization of various retry parameters:
16
+
17
+ ```python
18
+ class RetryConfig:
19
+ def __init__(
20
+ self,
21
+ max_retries: int = 5, # Maximum number of retry attempts
22
+ initial_delay: float = 1.0, # Initial delay between retries (seconds)
23
+ max_delay: float = 60.0, # Maximum delay between retries (seconds)
24
+ backoff_factor: float = 2.0, # Multiplier for delay after each retry
25
+ jitter: bool = True, # Add randomness to delay to prevent thundering herd
26
+ ):
27
+ ...
28
+ ```
29
+
30
+ ## Integration with MessageBus Worker
31
+
32
+ The RabbitMQ consumer in the message bus system uses the retry mechanism in several key areas:
33
+
34
+ 1. **Connection Establishment**: When establishing a connection to RabbitMQ, the system will automatically retry with increasing backoff periods if the connection fails.
35
+
36
+ 2. **Channel Creation**: When creating channels for publishing or consuming messages, failures trigger the retry mechanism.
37
+
38
+ 3. **Consumer Setup**: Setting up message consumers uses retry logic to handle temporary failures.
39
+
40
+ ## URL Configuration Parameters
41
+
42
+ Retry behavior can be customized through URL parameters when configuring the RabbitMQ connection:
43
+
44
+ | Parameter | Description | Default |
45
+ |-----------|-------------|---------|
46
+ | `connection_retry_max` | Maximum number of connection retry attempts | 5 |
47
+ | `connection_retry_delay` | Initial delay between connection retries (seconds) | 1.0 |
48
+ | `connection_retry_max_delay` | Maximum delay between connection retries (seconds) | 60.0 |
49
+ | `connection_retry_backoff` | Multiplier for delay after each connection retry | 2.0 |
50
+ | `consumer_retry_max` | Maximum number of consumer setup retry attempts | 3 |
51
+ | `consumer_retry_delay` | Initial delay between consumer setup retries (seconds) | 0.5 |
52
+ | `consumer_retry_max_delay` | Maximum delay between consumer setup retries (seconds) | 5.0 |
53
+ | `consumer_retry_backoff` | Multiplier for delay after each consumer setup retry | 2.0 |
54
+
55
+ ## Example Usage
56
+
57
+ ```python
58
+ # Configure with custom retry settings in URL:
59
+ broker_url = "amqp://guest:guest@localhost:5672/?exchange=jararaca&prefetch_count=10&connection_retry_max=10&connection_retry_delay=2.0"
60
+
61
+ # Use custom retry configuration in code:
62
+ from jararaca.utils.retry import RetryConfig, retry_with_backoff
63
+
64
+ config = RetryConfig(max_retries=3, initial_delay=1.0, max_delay=30.0)
65
+
66
+ async def connect_with_retry():
67
+ return await retry_with_backoff(
68
+ establish_connection,
69
+ retry_config=config,
70
+ retry_exceptions=(ConnectionError, TimeoutError)
71
+ )
72
+ ```
73
+
74
+ ## Benefits
75
+
76
+ 1. **Resilience** - The system can recover automatically from transient failures
77
+ 2. **Reduced downtime** - Automatic reconnection minimizes service disruption
78
+ 3. **Configuration flexibility** - Retry behavior can be tailored to different environments
79
+ 4. **Smart backoff** - Exponential backoff with jitter prevents overloading services during recovery
@@ -12,22 +12,16 @@ The Jararaca scheduler allows you to:
12
12
  - Distribute scheduled tasks across multiple instances
13
13
  - Handle delayed message execution
14
14
 
15
- The scheduler has two implementations:
16
- 1. **Basic Scheduler** - Simple scheduler for local execution
17
- 2. **Enhanced Scheduler (V2)** - Distributed scheduler with improved backend support and message broker integration
15
+ The scheduler is implemented through the BeatWorker which provides distributed task scheduling via a message broker:
18
16
 
19
17
  ```mermaid
20
18
  graph TD
21
- A[Microservice] --> B[Scheduler System]
22
- B --> C[Basic Scheduler]
23
- B --> D[Enhanced Scheduler V2]
24
-
25
- C --> E[Local Task Execution]
26
- D --> F[Message Broker]
27
- F --> G[Workers]
28
- D --> H[Backend Store]
29
- H --> I[Last Execution Time]
30
- H --> J[Delayed Messages]
19
+ A[Microservice] --> B[BeatWorker]
20
+ B --> C[Message Broker]
21
+ B --> D[Backend Store]
22
+ C --> E[Message Processing]
23
+ D --> F[Last Execution Time]
24
+ D --> G[Delayed Messages]
31
25
  ```
32
26
 
33
27
  ## Using the Scheduler
@@ -73,31 +67,57 @@ Jararaca uses standard cron expressions for scheduling. Here are some examples:
73
67
  - `0 0 * * 0` - Run at midnight every Sunday
74
68
  - `0 0 1 * *` - Run at midnight on the first day of every month
75
69
 
76
- ## Basic Scheduler Implementation
70
+ ## Using the BeatWorker Scheduler
77
71
 
78
- The basic scheduler is suitable for simpler applications where tasks run locally:
72
+ The BeatWorker scheduler provides distributed task execution through a message broker:
79
73
 
80
74
  ```python
81
75
  from jararaca import Microservice, ScheduledAction
76
+ from jararaca.scheduler.beat_worker import BeatWorker
82
77
 
83
78
  app = Microservice(
84
79
  # Your microservice configuration
85
80
  )
86
81
 
87
82
  # Run the scheduler
88
- from jararaca.scheduler.scheduler import Scheduler
89
-
90
- scheduler = Scheduler(app, interval=1)
91
- scheduler.run()
83
+ beat_worker = BeatWorker(
84
+ app=app,
85
+ interval=1,
86
+ backend_url="redis://localhost:6379",
87
+ broker_url="amqp://guest:guest@localhost:5672/?exchange=jararaca",
88
+ scheduled_action_names=None # Optional set of action names to run
89
+ )
90
+ beat_worker.run()
92
91
  ```
93
92
 
94
- ## Enhanced Scheduler V2 Implementation
93
+ You can also use the CLI command to run the scheduler:
95
94
 
96
- The V2 scheduler adds support for distributed execution and message broker integration, making it ideal for more complex applications:
95
+ ```bash
96
+ # Standard beat scheduler execution
97
+ jararaca beat app_module:app --interval 1 --broker-url "amqp://guest:guest@localhost:5672/?exchange=jararaca" --backend-url "redis://localhost:6379"
98
+
99
+ # With auto-reload for development (automatically restarts when Python files change)
100
+ jararaca beat app_module:app --interval 1 --broker-url "amqp://guest:guest@localhost:5672/?exchange=jararaca" --backend-url "redis://localhost:6379" --reload
101
+
102
+ # Using environment variables
103
+ export APP_PATH="app_module:app"
104
+ export INTERVAL="1"
105
+ export BROKER_URL="amqp://guest:guest@localhost:5672/?exchange=jararaca"
106
+ export BACKEND_URL="redis://localhost:6379"
107
+ export RELOAD="true"
108
+ export SRC_DIR="src"
109
+ jararaca beat
110
+ ```
97
111
 
98
- ```python
99
- from jararaca import Microservice, ScheduledAction
100
- from jararaca.scheduler.scheduler_v2 import SchedulerV2
112
+ All command options support environment variables:
113
+ - `APP_PATH`: The application module path [required]
114
+ - `INTERVAL`: Polling interval in seconds [default: 1]
115
+ - `BROKER_URL`: The URL for the message broker [required]
116
+ - `BACKEND_URL`: The URL for the message broker backend [required]
117
+ - `ACTIONS`: Comma-separated list of action names to run [optional]
118
+ - `RELOAD`: Enable auto-reload when Python files change [optional]
119
+ - `SRC_DIR`: The source directory to watch for changes when using reload [default: "src"]
120
+ ```
101
121
 
102
122
  app = Microservice(
103
123
  # Your microservice configuration
@@ -57,24 +57,38 @@ class WebSocketMessage(WebSocketMessageBase):
57
57
 
58
58
  ### 3. WebSocketConnectionManager
59
59
 
60
- Manages WebSocket connections, rooms, and message distribution:
60
+ A Protocol that defines the interface for managing WebSocket connections:
61
61
 
62
+ ```python
63
+ class WebSocketConnectionManager(Protocol):
64
+ async def broadcast(self, message: bytes) -> None: ...
65
+ async def send(self, rooms: list[str], message: WebSocketMessageBase) -> None: ...
66
+ async def join(self, rooms: list[str], websocket: WebSocket) -> None: ...
67
+ async def add_websocket(self, websocket: WebSocket) -> None: ...
68
+ async def remove_websocket(self, websocket: WebSocket) -> None: ...
69
+ ```
70
+
71
+ The WebSocketConnectionManager:
62
72
  - Maintains a registry of active WebSocket connections
63
73
  - Groups connections into named rooms
64
74
  - Provides methods for broadcasting and sending targeted messages
65
75
 
66
- ### 4. WebSocketConnectionBackend
76
+ ### 4. Context-based WebSocket Access
67
77
 
68
- A protocol defining the contract for backend implementations:
78
+ Jararaca uses context variables to provide access to WebSocket functionality anywhere in your application:
69
79
 
70
80
  ```python
71
- class WebSocketConnectionBackend(Protocol):
72
- async def broadcast(self, message: bytes) -> None: ...
73
- async def send(self, rooms: list[str], message: bytes) -> None: ...
74
- def configure(
75
- self, broadcast: BroadcastFunc, send: SendFunc, shutdown_event: asyncio.Event
76
- ) -> None: ...
77
- async def shutdown(self) -> None: ...
81
+ from jararaca.presentation.websocket.context import use_ws_manager, use_ws_message_sender
82
+
83
+ # Send a message to specific rooms
84
+ async def notify_users(message_data: dict, room_id: str):
85
+ message = UserNotificationMessage(**message_data)
86
+ await use_ws_message_sender().send([room_id], message)
87
+
88
+ # Or directly from a WebSocketMessage instance
89
+ async def send_update(update_data: dict, room_id: str):
90
+ message = SystemUpdateMessage(**update_data)
91
+ await message.send(room_id)
78
92
  ```
79
93
 
80
94
  ### 5. RedisWebSocketConnectionBackend
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "jararaca"
3
- version = "0.3.11a15"
3
+ version = "0.3.12a0"
4
4
  description = "A simple and fast API framework for Python"
5
5
  authors = ["Lucas S <me@luscasleo.dev>"]
6
6
  readme = "README.md"