jararaca 0.2.37a9__tar.gz → 0.2.37a11__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 (80) hide show
  1. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/PKG-INFO +1 -1
  2. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/pyproject.toml +1 -1
  3. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/__init__.py +7 -0
  4. jararaca-0.2.37a11/src/jararaca/messagebus/interceptors/aiopika_publisher_interceptor.py +131 -0
  5. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/presentation/decorators.py +53 -13
  6. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/tools/typescript/interface_parser.py +15 -0
  7. jararaca-0.2.37a9/src/jararaca/messagebus/interceptors/aiopika_publisher_interceptor.py +0 -76
  8. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/LICENSE +0 -0
  9. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/README.md +0 -0
  10. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/Architecture/Message Bus/Decorators.md +0 -0
  11. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/Architecture/Message Bus/Interceptors.md +0 -0
  12. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/Architecture/Observability/Decorators.md +0 -0
  13. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/Architecture/Observability/Interceptors.md +0 -0
  14. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/Architecture/Presentation/Decorators.md +0 -0
  15. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/Architecture/RPC/RestClients/Decorators.md +0 -0
  16. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/Architecture/RPC/RestClients/Middlewared.md +0 -0
  17. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/Architecture/Schedule/Decorators.md +0 -0
  18. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/Architecture/Websocket/Decorators.md +0 -0
  19. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/Architecture/Websocket/Interceptors.md +0 -0
  20. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/Concept/Adapters.md +0 -0
  21. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/Concept/Hexagonal Architecture.md +0 -0
  22. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/Concept/Ports.md +0 -0
  23. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.jpeg +0 -0
  24. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.webp +0 -0
  25. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/assets/tracing_example.png +0 -0
  26. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/docs/index.md +0 -0
  27. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/__main__.py +0 -0
  28. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/cli.py +0 -0
  29. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/common/__init__.py +0 -0
  30. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/core/__init__.py +0 -0
  31. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/core/providers.py +0 -0
  32. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/core/uow.py +0 -0
  33. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/di.py +0 -0
  34. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/files/entity.py.mako +0 -0
  35. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/lifecycle.py +0 -0
  36. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/messagebus/__init__.py +0 -0
  37. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/messagebus/bus_message_controller.py +0 -0
  38. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/messagebus/decorators.py +0 -0
  39. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/messagebus/interceptors/__init__.py +0 -0
  40. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/messagebus/publisher.py +0 -0
  41. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/messagebus/types.py +0 -0
  42. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/messagebus/worker.py +0 -0
  43. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/microservice.py +0 -0
  44. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/observability/decorators.py +0 -0
  45. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/observability/interceptor.py +0 -0
  46. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/observability/providers/__init__.py +0 -0
  47. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/observability/providers/otel.py +0 -0
  48. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/persistence/base.py +0 -0
  49. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/persistence/exports.py +0 -0
  50. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/persistence/interceptors/__init__.py +0 -0
  51. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/persistence/interceptors/aiosqa_interceptor.py +0 -0
  52. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/persistence/session.py +0 -0
  53. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/persistence/sort_filter.py +0 -0
  54. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/persistence/utilities.py +0 -0
  55. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/presentation/__init__.py +0 -0
  56. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/presentation/hooks.py +0 -0
  57. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/presentation/http_microservice.py +0 -0
  58. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/presentation/server.py +0 -0
  59. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/presentation/websocket/__init__.py +0 -0
  60. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/presentation/websocket/base_types.py +0 -0
  61. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/presentation/websocket/context.py +0 -0
  62. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/presentation/websocket/decorators.py +0 -0
  63. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/presentation/websocket/redis.py +0 -0
  64. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/presentation/websocket/types.py +0 -0
  65. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/presentation/websocket/websocket_interceptor.py +0 -0
  66. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/py.typed +0 -0
  67. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/rpc/__init__.py +0 -0
  68. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/rpc/http/__init__.py +0 -0
  69. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/rpc/http/backends/__init__.py +0 -0
  70. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/rpc/http/backends/httpx.py +0 -0
  71. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/rpc/http/backends/otel.py +0 -0
  72. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/rpc/http/decorators.py +0 -0
  73. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/rpc/http/httpx.py +0 -0
  74. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/scheduler/__init__.py +0 -0
  75. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/scheduler/decorators.py +0 -0
  76. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/scheduler/scheduler.py +0 -0
  77. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/tools/app_config/__init__.py +0 -0
  78. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/tools/app_config/decorators.py +0 -0
  79. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/tools/app_config/interceptor.py +0 -0
  80. {jararaca-0.2.37a9 → jararaca-0.2.37a11}/src/jararaca/tools/metadata.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jararaca
3
- Version: 0.2.37a9
3
+ Version: 0.2.37a11
4
4
  Summary: A simple and fast API framework for Python
5
5
  Home-page: https://github.com/LuscasLeo/jararaca
6
6
  Author: Lucas S
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "jararaca"
3
- version = "0.2.37a9"
3
+ version = "0.2.37a11"
4
4
  description = "A simple and fast API framework for Python"
5
5
  authors = ["Lucas S <me@luscasleo.dev>"]
6
6
  readme = "README.md"
@@ -59,6 +59,7 @@ if TYPE_CHECKING:
59
59
  from .messagebus.decorators import MessageBusController, MessageHandler
60
60
  from .messagebus.interceptors.aiopika_publisher_interceptor import (
61
61
  AIOPikaConnectionFactory,
62
+ GenericPoolConfig,
62
63
  MessageBusPublisherInterceptor,
63
64
  )
64
65
  from .messagebus.publisher import use_publisher
@@ -192,6 +193,7 @@ if TYPE_CHECKING:
192
193
  "Put",
193
194
  "Delete",
194
195
  "use_publisher",
196
+ "GenericPoolConfig",
195
197
  "AIOPikaConnectionFactory",
196
198
  "MessageBusPublisherInterceptor",
197
199
  "RedisWebSocketConnectionBackend",
@@ -221,6 +223,11 @@ _dynamic_imports: "dict[str, tuple[str, str, str | None]]" = {
221
223
  "messagebus.bus_message_controller",
222
224
  None,
223
225
  ),
226
+ "GenericPoolConfig": (
227
+ __SPEC_PARENT__,
228
+ "messagebus.interceptors.aiopika_publisher_interceptor",
229
+ None,
230
+ ),
224
231
  "ack": (__SPEC_PARENT__, "messagebus.bus_message_controller", None),
225
232
  "nack": (__SPEC_PARENT__, "messagebus.bus_message_controller", None),
226
233
  "reject": (__SPEC_PARENT__, "messagebus.bus_message_controller", None),
@@ -0,0 +1,131 @@
1
+ from contextlib import asynccontextmanager
2
+ from typing import Any, AsyncContextManager, AsyncGenerator, Protocol
3
+
4
+ import aio_pika
5
+ from aio_pika.abc import AbstractConnection
6
+ from pydantic import BaseModel
7
+
8
+ from jararaca.messagebus.publisher import MessagePublisher, provide_message_publisher
9
+ from jararaca.microservice import AppContext, AppInterceptor
10
+
11
+
12
+ class MessageBusConnectionFactory(Protocol):
13
+
14
+ def provide_connection(self) -> AsyncContextManager[MessagePublisher]: ...
15
+
16
+
17
+ class MessageBusPublisherInterceptor(AppInterceptor):
18
+
19
+ def __init__(
20
+ self,
21
+ connection_factory: MessageBusConnectionFactory,
22
+ connection_name: str = "default",
23
+ ):
24
+ self.connection_factory = connection_factory
25
+ self.connection_name = connection_name
26
+
27
+ @asynccontextmanager
28
+ async def intercept(self, app_context: AppContext) -> AsyncGenerator[None, None]:
29
+ if app_context.context_type == "websocket":
30
+ yield
31
+ return
32
+
33
+ async with self.connection_factory.provide_connection() as connection:
34
+ with provide_message_publisher(self.connection_name, connection):
35
+ yield
36
+
37
+
38
+ class AIOPikaMessagePublisher(MessagePublisher):
39
+
40
+ def __init__(self, channel: aio_pika.abc.AbstractChannel, exchange_name: str):
41
+ self.channel = channel
42
+ self.exchange_name = exchange_name
43
+
44
+ async def publish(self, message: BaseModel, topic: str) -> None:
45
+ exchange = await self.channel.declare_exchange(
46
+ self.exchange_name,
47
+ type=aio_pika.ExchangeType.TOPIC,
48
+ )
49
+ routing_key = f"{self.exchange_name}.{topic}."
50
+ await exchange.publish(
51
+ aio_pika.Message(body=message.model_dump_json().encode()),
52
+ routing_key=routing_key,
53
+ )
54
+
55
+
56
+ class GenericPoolConfig(BaseModel):
57
+ max_size: int
58
+
59
+
60
+ class AIOPikaConnectionFactory(MessageBusConnectionFactory):
61
+
62
+ def __init__(
63
+ self,
64
+ url: str,
65
+ exchange: str,
66
+ connection_pool_config: GenericPoolConfig | None = None,
67
+ channel_pool_config: GenericPoolConfig | None = None,
68
+ ):
69
+ self.url = url
70
+ self.exchange = exchange
71
+
72
+ self.connection_pool: aio_pika.pool.Pool[AbstractConnection] | None = None
73
+ self.channel_pool: aio_pika.pool.Pool[aio_pika.abc.AbstractChannel] | None = (
74
+ None
75
+ )
76
+
77
+ if connection_pool_config:
78
+
79
+ async def get_connection() -> AbstractConnection:
80
+ return await aio_pika.connect_robust(self.url)
81
+
82
+ self.connection_pool = aio_pika.pool.Pool[AbstractConnection](
83
+ get_connection,
84
+ max_size=connection_pool_config.max_size,
85
+ )
86
+
87
+ if channel_pool_config:
88
+
89
+ async def get_channel() -> aio_pika.abc.AbstractChannel:
90
+ async with self.acquire_connection() as connection:
91
+ return await connection.channel(publisher_confirms=False)
92
+
93
+ self.channel_pool = aio_pika.pool.Pool[aio_pika.abc.AbstractChannel](
94
+ get_channel, max_size=channel_pool_config.max_size
95
+ )
96
+
97
+ @asynccontextmanager
98
+ async def acquire_connection(self) -> AsyncGenerator[AbstractConnection, Any]:
99
+ if not self.connection_pool:
100
+ async with await aio_pika.connect_robust(self.url) as connection:
101
+ yield connection
102
+ else:
103
+
104
+ async with self.connection_pool.acquire() as connection:
105
+ yield connection
106
+
107
+ @asynccontextmanager
108
+ async def acquire_channel(
109
+ self,
110
+ ) -> AsyncGenerator[aio_pika.abc.AbstractChannel, Any]:
111
+ if not self.channel_pool:
112
+ async with self.acquire_connection() as connection:
113
+ yield await connection.channel(publisher_confirms=False)
114
+ else:
115
+ async with self.channel_pool.acquire() as channel:
116
+ yield channel
117
+
118
+ @asynccontextmanager
119
+ async def provide_connection(self) -> AsyncGenerator[AIOPikaMessagePublisher, Any]:
120
+
121
+ async with self.acquire_channel() as channel:
122
+ tx = channel.transaction()
123
+
124
+ await tx.select()
125
+
126
+ try:
127
+ yield AIOPikaMessagePublisher(channel, exchange_name=self.exchange)
128
+ await tx.commit()
129
+ except Exception as e:
130
+ await tx.rollback()
131
+ raise e
@@ -1,5 +1,5 @@
1
1
  import inspect
2
- from typing import Any, Callable, Protocol, TypeVar, cast
2
+ from typing import Any, Callable, Literal, Protocol, TypeVar, cast
3
3
 
4
4
  from fastapi import APIRouter
5
5
  from fastapi import Depends as DependsF
@@ -147,6 +147,16 @@ class RestController:
147
147
 
148
148
  Options = dict[str, Any]
149
149
 
150
+ ResponseType = Literal[
151
+ "arraybuffer",
152
+ "blob",
153
+ "document",
154
+ "json",
155
+ "text",
156
+ "stream",
157
+ "formdata",
158
+ ]
159
+
150
160
 
151
161
  class HttpMapping:
152
162
 
@@ -154,11 +164,16 @@ class HttpMapping:
154
164
  ORDER_COUNTER = 0
155
165
 
156
166
  def __init__(
157
- self, method: str, path: str = "/", options: Options | None = None
167
+ self,
168
+ method: str,
169
+ path: str = "/",
170
+ adapter_options: Options | None = None,
171
+ response_type: ResponseType | None = None,
158
172
  ) -> None:
159
173
  self.method = method
160
174
  self.path = path
161
- self.options = options
175
+ self.options = adapter_options
176
+ self.response_type = response_type
162
177
 
163
178
  HttpMapping.ORDER_COUNTER += 1
164
179
  self.order = HttpMapping.ORDER_COUNTER
@@ -185,32 +200,57 @@ class HttpMapping:
185
200
 
186
201
  class Post(HttpMapping):
187
202
 
188
- def __init__(self, path: str = "/", options: Options | None = None) -> None:
189
- super().__init__("POST", path, options)
203
+ def __init__(
204
+ self,
205
+ path: str = "/",
206
+ options: Options | None = None,
207
+ response_type: ResponseType | None = None,
208
+ ) -> None:
209
+ super().__init__("POST", path, options, response_type)
190
210
 
191
211
 
192
212
  class Get(HttpMapping):
193
213
 
194
- def __init__(self, path: str = "/", options: Options | None = None) -> None:
195
- super().__init__("GET", path, options)
214
+ def __init__(
215
+ self,
216
+ path: str = "/",
217
+ options: Options | None = None,
218
+ response_type: ResponseType | None = None,
219
+ ) -> None:
220
+ super().__init__("GET", path, options, response_type)
196
221
 
197
222
 
198
223
  class Put(HttpMapping):
199
224
 
200
- def __init__(self, path: str = "/", options: Options | None = None) -> None:
201
- super().__init__("PUT", path, options)
225
+ def __init__(
226
+ self,
227
+ path: str = "/",
228
+ options: Options | None = None,
229
+ response_type: ResponseType | None = None,
230
+ ) -> None:
231
+ super().__init__("PUT", path, options, response_type)
202
232
 
203
233
 
204
234
  class Delete(HttpMapping):
205
235
 
206
- def __init__(self, path: str = "/", options: Options | None = None) -> None:
207
- super().__init__("DELETE", path, options)
236
+ def __init__(
237
+ self,
238
+ path: str = "/",
239
+ options: Options | None = None,
240
+ response_type: ResponseType | None = None,
241
+ ) -> None:
242
+ super().__init__("DELETE", path, options, response_type)
208
243
 
209
244
 
210
245
  class Patch(HttpMapping):
211
246
 
212
- def __init__(self, path: str = "/", options: Options | None = None) -> None:
213
- super().__init__("PATCH", path, options)
247
+ def __init__(
248
+ self,
249
+ path: str = "/",
250
+ options: Options | None = None,
251
+ response_type: ResponseType | None = None,
252
+ ) -> None:
253
+ super().__init__("PATCH", path, options, response_type)
214
254
 
215
255
 
216
256
  class UseMiddleware:
@@ -85,6 +85,8 @@ def parse_literal_value(value: Any) -> str:
85
85
 
86
86
 
87
87
  def get_field_type_for_ts(field_type: Any) -> Any:
88
+ if field_type is Response:
89
+ return "unknown"
88
90
  if field_type is Any:
89
91
  return "any"
90
92
  if field_type == UploadFile:
@@ -367,12 +369,23 @@ export type WebSocketMessageMap = {
367
369
 
368
370
  final_buffer.write(
369
371
  """
372
+ export type ResponseType =
373
+ | "arraybuffer"
374
+ | "blob"
375
+ | "document"
376
+ | "json"
377
+ | "text"
378
+ | "stream"
379
+ | "formdata";
380
+
381
+
370
382
  export interface HttpBackendRequest {
371
383
  method: string;
372
384
  path: string;
373
385
  headers: { [key: string]: string };
374
386
  query: { [key: string]: unknown };
375
387
  body: unknown;
388
+ responseType?: ResponseType;
376
389
  }
377
390
 
378
391
  export interface HttpBackend {
@@ -491,6 +504,8 @@ def write_rest_controller_to_typescript_interface(
491
504
  "const response = await this.httpBackend.request<%s>({ \n"
492
505
  % return_value_repr
493
506
  )
507
+ if mapping.response_type is not None:
508
+ class_buffer.write(f'\t\t\tresponseType: "{mapping.response_type}",\n')
494
509
  class_buffer.write(f'\t\t\tmethod: "{mapping.method}",\n')
495
510
 
496
511
  endpoint_path = parse_path_with_params(mapping.path, arg_params_spec)
@@ -1,76 +0,0 @@
1
- from contextlib import asynccontextmanager
2
- from typing import Any, AsyncContextManager, AsyncGenerator, Protocol
3
-
4
- import aio_pika
5
- from pydantic import BaseModel
6
-
7
- from jararaca.messagebus.publisher import MessagePublisher, provide_message_publisher
8
- from jararaca.microservice import AppContext, AppInterceptor
9
-
10
-
11
- class MessageBusConnectionFactory(Protocol):
12
-
13
- def provide_connection(self) -> AsyncContextManager[MessagePublisher]: ...
14
-
15
-
16
- class MessageBusPublisherInterceptor(AppInterceptor):
17
-
18
- def __init__(
19
- self,
20
- connection_factory: MessageBusConnectionFactory,
21
- connection_name: str = "default",
22
- ):
23
- self.connection_factory = connection_factory
24
- self.connection_name = connection_name
25
-
26
- @asynccontextmanager
27
- async def intercept(self, app_context: AppContext) -> AsyncGenerator[None, None]:
28
- async with self.connection_factory.provide_connection() as connection:
29
- with provide_message_publisher(self.connection_name, connection):
30
- yield
31
-
32
-
33
- class AIOPikaMessagePublisher(MessagePublisher):
34
-
35
- def __init__(self, channel: aio_pika.abc.AbstractChannel, exchange_name: str):
36
- self.channel = channel
37
- self.exchange_name = exchange_name
38
-
39
- async def publish(self, message: BaseModel, topic: str) -> None:
40
- exchange = await self.channel.declare_exchange(
41
- self.exchange_name,
42
- type=aio_pika.ExchangeType.TOPIC,
43
- )
44
- routing_key = f"{self.exchange_name}.{topic}."
45
- await exchange.publish(
46
- aio_pika.Message(body=message.model_dump_json().encode()),
47
- routing_key=routing_key,
48
- )
49
-
50
-
51
- class AIOPikaConnectionFactory(MessageBusConnectionFactory):
52
-
53
- def __init__(
54
- self,
55
- url: str,
56
- exchange: str,
57
- ):
58
- self.url = url
59
- self.exchange = exchange
60
-
61
- @asynccontextmanager
62
- async def provide_connection(self) -> AsyncGenerator[AIOPikaMessagePublisher, Any]:
63
- connection = await aio_pika.connect_robust(self.url)
64
- async with connection:
65
- async with connection.channel(publisher_confirms=False) as channel:
66
-
67
- tx = channel.transaction()
68
-
69
- await tx.select()
70
-
71
- try:
72
- yield AIOPikaMessagePublisher(channel, exchange_name=self.exchange)
73
- await tx.commit()
74
- except Exception as e:
75
- await tx.rollback()
76
- raise e
File without changes
File without changes
File without changes