jararaca 0.3.12a1__tar.gz → 0.3.12a3__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.12a1 → jararaca-0.3.12a3}/PKG-INFO +1 -1
- jararaca-0.3.12a3/docs/interceptors.md +210 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/pyproject.toml +1 -1
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/scheduler/beat_worker.py +14 -6
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/tools/typescript/interface_parser.py +18 -4
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/LICENSE +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/README.md +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/docs/CNAME +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/docs/architecture.md +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.jpeg +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.webp +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/docs/assets/tracing_example.png +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/docs/index.md +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/docs/messagebus.md +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/docs/retry.md +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/docs/scheduler.md +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/docs/stylesheets/custom.css +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/docs/websocket.md +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/__main__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/broker_backend/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/broker_backend/mapper.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/broker_backend/redis_broker_backend.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/cli.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/common/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/core/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/core/providers.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/core/uow.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/di.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/files/entity.py.mako +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/lifecycle.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/messagebus/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/messagebus/bus_message_controller.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/messagebus/consumers/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/messagebus/decorators.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/messagebus/interceptors/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/messagebus/interceptors/aiopika_publisher_interceptor.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/messagebus/interceptors/publisher_interceptor.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/messagebus/message.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/messagebus/publisher.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/messagebus/worker.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/microservice.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/observability/decorators.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/observability/interceptor.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/observability/providers/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/observability/providers/otel.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/persistence/base.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/persistence/exports.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/persistence/interceptors/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/persistence/interceptors/aiosqa_interceptor.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/persistence/session.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/persistence/sort_filter.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/persistence/utilities.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/presentation/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/presentation/decorators.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/presentation/hooks.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/presentation/http_microservice.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/presentation/server.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/presentation/websocket/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/presentation/websocket/base_types.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/presentation/websocket/context.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/presentation/websocket/decorators.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/presentation/websocket/redis.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/presentation/websocket/types.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/presentation/websocket/websocket_interceptor.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/py.typed +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/reflect/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/reflect/controller_inspect.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/reflect/metadata.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/rpc/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/rpc/http/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/rpc/http/backends/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/rpc/http/backends/httpx.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/rpc/http/backends/otel.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/rpc/http/decorators.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/rpc/http/httpx.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/scheduler/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/scheduler/decorators.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/scheduler/types.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/tools/app_config/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/tools/app_config/decorators.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/tools/app_config/interceptor.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/utils/__init__.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/utils/rabbitmq_utils.py +0 -0
- {jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/utils/retry.py +0 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# Interceptors in Jararaca
|
|
2
|
+
|
|
3
|
+
Interceptors are a powerful mechanism in Jararaca for implementing cross-cutting concerns across different execution contexts. They allow you to wrap the execution of HTTP requests, message handling, scheduled tasks, and WebSocket communications with common behaviors such as transaction management, message publishing, and WebSocket message dispatching.
|
|
4
|
+
|
|
5
|
+
## Overview of the Interceptor System
|
|
6
|
+
|
|
7
|
+
Interceptors in Jararaca work by wrapping the execution of handlers in different contexts:
|
|
8
|
+
|
|
9
|
+
- **HTTP Controllers**: Intercept incoming HTTP requests before they reach controllers
|
|
10
|
+
- **Message Bus Consumers**: Intercept message processing in workers
|
|
11
|
+
- **Scheduled Tasks**: Intercept scheduled task execution
|
|
12
|
+
- **WebSocket Connections**: Manage WebSocket connections and message dispatching
|
|
13
|
+
|
|
14
|
+
Each interceptor provides a specific capability to the application through context variables, allowing your code to access these capabilities through hook functions like `use_session()`, `use_publisher()`, and `use_ws_manager()`.
|
|
15
|
+
|
|
16
|
+
## The Atomic Layer: Transactions, Messages, and WebSockets
|
|
17
|
+
|
|
18
|
+
The true power of the interceptor system lies in how it creates an atomic layer that ensures consistency across database operations, message publishing, and WebSocket communications. This is particularly important for implementing transactional outbox patterns and ensuring consistency in distributed systems.
|
|
19
|
+
|
|
20
|
+
```mermaid
|
|
21
|
+
sequenceDiagram
|
|
22
|
+
participant Client
|
|
23
|
+
participant HTTP Context
|
|
24
|
+
participant DB Interceptor
|
|
25
|
+
participant MessageBus Interceptor
|
|
26
|
+
participant WebSocket Interceptor
|
|
27
|
+
participant Database
|
|
28
|
+
participant MessageBroker
|
|
29
|
+
participant WebSocketBackend
|
|
30
|
+
|
|
31
|
+
Client->>HTTP Context: HTTP Request
|
|
32
|
+
Note over HTTP Context,WebSocketBackend: Transaction Boundary Begins
|
|
33
|
+
|
|
34
|
+
HTTP Context->>DB Interceptor: Begin Transaction
|
|
35
|
+
DB Interceptor->>Database: Begin DB Transaction
|
|
36
|
+
|
|
37
|
+
HTTP Context->>MessageBus Interceptor: Stage Messages
|
|
38
|
+
MessageBus Interceptor->>MessageBus Interceptor: Queue Messages
|
|
39
|
+
|
|
40
|
+
HTTP Context->>WebSocket Interceptor: Stage WebSocket Messages
|
|
41
|
+
WebSocket Interceptor->>WebSocket Interceptor: Queue WebSocket Messages
|
|
42
|
+
|
|
43
|
+
HTTP Context->>DB Interceptor: Commit Transaction
|
|
44
|
+
DB Interceptor->>Database: Commit DB Transaction
|
|
45
|
+
Database-->>DB Interceptor: Success
|
|
46
|
+
|
|
47
|
+
DB Interceptor-->>MessageBus Interceptor: DB Commit Success
|
|
48
|
+
MessageBus Interceptor->>MessageBroker: Flush Queued Messages
|
|
49
|
+
|
|
50
|
+
MessageBus Interceptor-->>WebSocket Interceptor: Messages Published
|
|
51
|
+
WebSocket Interceptor->>WebSocketBackend: Flush WebSocket Messages
|
|
52
|
+
|
|
53
|
+
Note over HTTP Context,WebSocketBackend: Transaction Boundary Ends
|
|
54
|
+
|
|
55
|
+
HTTP Context-->>Client: HTTP Response
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Order of Interceptors Matters
|
|
59
|
+
|
|
60
|
+
The order in which interceptors are configured in your application is critical. The typical order is:
|
|
61
|
+
|
|
62
|
+
1. **Configuration Interceptor** - Loads and provides application configuration
|
|
63
|
+
2. **Message Bus Publisher Interceptor** - Provides message publishing capabilities
|
|
64
|
+
3. **Database Session Interceptor** - Provides database transaction capabilities
|
|
65
|
+
4. **WebSocket Interceptor** - Provides WebSocket communication capabilities
|
|
66
|
+
|
|
67
|
+
This order ensures that:
|
|
68
|
+
|
|
69
|
+
1. The database transaction is committed first
|
|
70
|
+
2. Only after successful database commit, messages are published to the message broker
|
|
71
|
+
3. Finally, WebSocket messages are dispatched to connected clients
|
|
72
|
+
|
|
73
|
+
## Implementing Transactional Outbox Pattern
|
|
74
|
+
|
|
75
|
+
Jararaca's interceptor system makes implementing the transactional outbox pattern straightforward. This pattern ensures that database changes and message publishing are atomic:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from jararaca.persistence.session import use_session
|
|
79
|
+
from jararaca.messagebus.publisher import use_publisher
|
|
80
|
+
|
|
81
|
+
async def create_user(user_data: dict):
|
|
82
|
+
# Get the current database session from the context
|
|
83
|
+
session = use_session()
|
|
84
|
+
|
|
85
|
+
# Get the message publisher from the context
|
|
86
|
+
publisher = use_publisher()
|
|
87
|
+
|
|
88
|
+
# Create user in database
|
|
89
|
+
new_user = User(**user_data)
|
|
90
|
+
session.add(new_user)
|
|
91
|
+
|
|
92
|
+
# Stage a message to be published after successful transaction
|
|
93
|
+
await publisher.publish("user_created", UserCreatedEvent(id=new_user.id))
|
|
94
|
+
|
|
95
|
+
# The actual database commit and message publishing
|
|
96
|
+
# happens automatically when the request handling is complete,
|
|
97
|
+
# managed by the interceptors
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
When this code executes:
|
|
101
|
+
1. The database session interceptor ensures the user is committed to the database
|
|
102
|
+
2. If the database transaction succeeds, the message bus interceptor publishes the staged message
|
|
103
|
+
3. If the database transaction fails, no messages are published
|
|
104
|
+
|
|
105
|
+
## Contexts and Interceptors
|
|
106
|
+
|
|
107
|
+
Jararaca supports different execution contexts, and interceptors behave differently in each:
|
|
108
|
+
|
|
109
|
+
### HTTP Context
|
|
110
|
+
|
|
111
|
+
In an HTTP context, all interceptors are active:
|
|
112
|
+
- Database Session Interceptor manages transactions
|
|
113
|
+
- Message Bus Publisher Interceptor stages and flushes messages
|
|
114
|
+
- WebSocket Interceptor stages and flushes WebSocket messages
|
|
115
|
+
|
|
116
|
+
### Worker Context
|
|
117
|
+
|
|
118
|
+
In a message bus worker context:
|
|
119
|
+
- Database Session Interceptor manages transactions
|
|
120
|
+
- Message Bus Publisher Interceptor stages and flushes messages
|
|
121
|
+
- WebSocket Interceptor stages and flushes WebSocket messages
|
|
122
|
+
|
|
123
|
+
### Scheduler Context
|
|
124
|
+
|
|
125
|
+
In a scheduler context:
|
|
126
|
+
- Database Session Interceptor manages transactions
|
|
127
|
+
- Message Bus Publisher Interceptor stages and flushes messages
|
|
128
|
+
- WebSocket Interceptor stages and flushes WebSocket messages
|
|
129
|
+
|
|
130
|
+
### WebSocket Context
|
|
131
|
+
|
|
132
|
+
In a WebSocket context:
|
|
133
|
+
- Database Session Interceptor manages transactions
|
|
134
|
+
- Message Bus Publisher is usually not active (as defined in the `intercept` method)
|
|
135
|
+
- WebSocket communications are managed directly
|
|
136
|
+
|
|
137
|
+
## Code Example: Configuring Interceptors
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
from jararaca import Microservice
|
|
141
|
+
from jararaca.persistence.interceptors import AIOSqlAlchemySessionInterceptor, AIOSQAConfig
|
|
142
|
+
from jararaca.messagebus.interceptors import MessageBusPublisherInterceptor
|
|
143
|
+
from jararaca.presentation.websocket import WebSocketInterceptor
|
|
144
|
+
|
|
145
|
+
# Create the microservice
|
|
146
|
+
microservice = Microservice(
|
|
147
|
+
name="my-service",
|
|
148
|
+
interceptors=[
|
|
149
|
+
# Configuration interceptor (if any)
|
|
150
|
+
# ...
|
|
151
|
+
|
|
152
|
+
# Message bus interceptor
|
|
153
|
+
lambda config: MessageBusPublisherInterceptor(
|
|
154
|
+
connection_factory=message_publisher_factory,
|
|
155
|
+
connection_name="default",
|
|
156
|
+
message_scheduler=message_scheduler,
|
|
157
|
+
),
|
|
158
|
+
|
|
159
|
+
# Database session interceptor
|
|
160
|
+
lambda config: AIOSqlAlchemySessionInterceptor(
|
|
161
|
+
AIOSQAConfig(
|
|
162
|
+
url="postgresql+asyncpg://user:password@localhost/dbname",
|
|
163
|
+
connection_name="default",
|
|
164
|
+
inject_default=True,
|
|
165
|
+
)
|
|
166
|
+
),
|
|
167
|
+
|
|
168
|
+
# WebSocket interceptor
|
|
169
|
+
lambda config: WebSocketInterceptor(
|
|
170
|
+
backend=redis_websocket_backend,
|
|
171
|
+
),
|
|
172
|
+
],
|
|
173
|
+
# Other microservice configuration...
|
|
174
|
+
)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Best Practices
|
|
178
|
+
|
|
179
|
+
1. **Order Matters**: Always configure interceptors in the order: configuration → message bus → database → WebSocket
|
|
180
|
+
2. **Transaction Boundaries**: Be aware that interceptors create implicit transaction boundaries
|
|
181
|
+
3. **Error Handling**: Database errors will prevent message publishing and WebSocket dispatching
|
|
182
|
+
4. **Idempotency**: Design your message handlers to be idempotent in case of retries
|
|
183
|
+
5. **Context Variables**: Use the appropriate context hooks (`use_session()`, `use_publisher()`, etc.) to access the capabilities provided by interceptors
|
|
184
|
+
|
|
185
|
+
## Advanced Usage: Custom Interceptors
|
|
186
|
+
|
|
187
|
+
You can create custom interceptors by implementing the `AppInterceptor` interface:
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
from contextlib import asynccontextmanager
|
|
191
|
+
from typing import AsyncGenerator
|
|
192
|
+
from jararaca.microservice import AppInterceptor, AppTransactionContext
|
|
193
|
+
|
|
194
|
+
class CustomInterceptor(AppInterceptor):
|
|
195
|
+
@asynccontextmanager
|
|
196
|
+
async def intercept(self, app_context: AppTransactionContext) -> AsyncGenerator[None, None]:
|
|
197
|
+
# Pre-processing logic
|
|
198
|
+
|
|
199
|
+
try:
|
|
200
|
+
# Let the request handler execute
|
|
201
|
+
yield
|
|
202
|
+
# Post-processing after successful execution
|
|
203
|
+
except Exception as e:
|
|
204
|
+
# Handle exceptions
|
|
205
|
+
raise e
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Conclusion
|
|
209
|
+
|
|
210
|
+
Jararaca's interceptor system provides a powerful way to implement cross-cutting concerns and ensure consistency across database operations, message publishing, and WebSocket communications. By properly configuring interceptors, you can implement patterns like the transactional outbox pattern with minimal effort, ensuring that your distributed system maintains consistency even in the face of failures.
|
|
@@ -5,7 +5,6 @@ import signal
|
|
|
5
5
|
import time
|
|
6
6
|
from abc import ABC, abstractmethod
|
|
7
7
|
from datetime import UTC, datetime
|
|
8
|
-
from types import FrameType
|
|
9
8
|
from typing import Any
|
|
10
9
|
from urllib.parse import parse_qs
|
|
11
10
|
|
|
@@ -249,13 +248,16 @@ class BeatWorker:
|
|
|
249
248
|
|
|
250
249
|
def run(self) -> None:
|
|
251
250
|
|
|
252
|
-
def
|
|
253
|
-
logger.info("
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
signal.signal(signal.SIGINT, on_signal_received)
|
|
251
|
+
def on_shutdown(loop: asyncio.AbstractEventLoop) -> None:
|
|
252
|
+
logger.info("Shutting down - signal received")
|
|
253
|
+
# Schedule the shutdown to run in the event loop
|
|
254
|
+
asyncio.create_task(self._graceful_shutdown())
|
|
257
255
|
|
|
258
256
|
with asyncio.Runner(loop_factory=uvloop.new_event_loop) as runner:
|
|
257
|
+
loop = runner.get_loop()
|
|
258
|
+
loop.add_signal_handler(signal.SIGINT, on_shutdown, loop)
|
|
259
|
+
# Add graceful shutdown handler for SIGTERM as well
|
|
260
|
+
loop.add_signal_handler(signal.SIGTERM, on_shutdown, loop)
|
|
259
261
|
runner.run(self.start_scheduler())
|
|
260
262
|
|
|
261
263
|
async def start_scheduler(self) -> None:
|
|
@@ -340,3 +342,9 @@ class BeatWorker:
|
|
|
340
342
|
|
|
341
343
|
await self.backend.dispose()
|
|
342
344
|
await self.broker.dispose()
|
|
345
|
+
|
|
346
|
+
async def _graceful_shutdown(self) -> None:
|
|
347
|
+
"""Handles graceful shutdown process"""
|
|
348
|
+
logger.info("Initiating graceful shutdown sequence")
|
|
349
|
+
self.shutdown_event.set()
|
|
350
|
+
logger.info("Graceful shutdown completed")
|
|
@@ -603,8 +603,19 @@ class HttpParemeterSpec:
|
|
|
603
603
|
|
|
604
604
|
|
|
605
605
|
def parse_path_with_params(path: str, parameters: list[HttpParemeterSpec]) -> str:
|
|
606
|
+
# Use a regular expression to match both simple parameters {param} and
|
|
607
|
+
# parameters with converters {param:converter}
|
|
608
|
+
import re
|
|
609
|
+
|
|
610
|
+
pattern = re.compile(r"{([^:}]+)(?::[^}]*)?}")
|
|
611
|
+
|
|
612
|
+
# For each parameter found in the path, replace it with :param format
|
|
606
613
|
for parameter in parameters:
|
|
607
|
-
path =
|
|
614
|
+
path = pattern.sub(
|
|
615
|
+
lambda m: f":{m.group(1)}" if m.group(1) == parameter.name else m.group(0),
|
|
616
|
+
path,
|
|
617
|
+
)
|
|
618
|
+
|
|
608
619
|
return path
|
|
609
620
|
|
|
610
621
|
|
|
@@ -728,7 +739,9 @@ def extract_parameters(
|
|
|
728
739
|
)
|
|
729
740
|
mapped_types.update(rec_mapped_types)
|
|
730
741
|
parameters_list.extend(rec_parameters)
|
|
731
|
-
elif
|
|
742
|
+
elif (
|
|
743
|
+
re.search(f":{parameter_name}(?:/|$)", controller.path) is not None
|
|
744
|
+
):
|
|
732
745
|
mapped_types.add(annotated_type)
|
|
733
746
|
parameters_list.append(
|
|
734
747
|
HttpParemeterSpec(
|
|
@@ -762,8 +775,9 @@ def extract_parameters(
|
|
|
762
775
|
)
|
|
763
776
|
)
|
|
764
777
|
elif (
|
|
765
|
-
|
|
766
|
-
|
|
778
|
+
# Match both simple parameters {param} and parameters with converters {param:converter}
|
|
779
|
+
re.search(f"{{{parameter_name}(:.*?)?}}", controller.path) is not None
|
|
780
|
+
or re.search(f"{{{parameter_name}(:.*?)?}}", mapping.path) is not None
|
|
767
781
|
):
|
|
768
782
|
mapped_types.add(parameter_type)
|
|
769
783
|
parameters_list.append(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jararaca-0.3.12a1 → jararaca-0.3.12a3}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.jpeg
RENAMED
|
File without changes
|
{jararaca-0.3.12a1 → jararaca-0.3.12a3}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.webp
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/persistence/interceptors/aiosqa_interceptor.py
RENAMED
|
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
|
{jararaca-0.3.12a1 → jararaca-0.3.12a3}/src/jararaca/presentation/websocket/websocket_interceptor.py
RENAMED
|
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
|