jararaca 0.2.37a11__py3-none-any.whl → 0.3.0__py3-none-any.whl
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/__init__.py +13 -4
- jararaca/broker_backend/__init__.py +102 -0
- jararaca/broker_backend/mapper.py +21 -0
- jararaca/broker_backend/redis_broker_backend.py +162 -0
- jararaca/cli.py +156 -21
- jararaca/messagebus/__init__.py +1 -1
- jararaca/messagebus/consumers/__init__.py +0 -0
- jararaca/messagebus/decorators.py +57 -21
- jararaca/messagebus/interceptors/aiopika_publisher_interceptor.py +51 -31
- jararaca/messagebus/interceptors/publisher_interceptor.py +34 -0
- jararaca/messagebus/message.py +27 -0
- jararaca/messagebus/publisher.py +31 -2
- jararaca/messagebus/worker.py +23 -27
- jararaca/messagebus/worker_v2.py +608 -0
- jararaca/microservice.py +1 -1
- jararaca/scheduler/decorators.py +34 -1
- jararaca/scheduler/scheduler.py +16 -9
- jararaca/scheduler/scheduler_v2.py +346 -0
- jararaca/scheduler/types.py +7 -0
- jararaca/utils/__init__.py +0 -0
- jararaca/utils/rabbitmq_utils.py +84 -0
- jararaca-0.3.0.dist-info/METADATA +156 -0
- {jararaca-0.2.37a11.dist-info → jararaca-0.3.0.dist-info}/RECORD +26 -19
- {jararaca-0.2.37a11.dist-info → jararaca-0.3.0.dist-info}/WHEEL +1 -1
- README.md +0 -243
- jararaca/messagebus/types.py +0 -30
- jararaca-0.2.37a11.dist-info/LICENSE +0 -674
- jararaca-0.2.37a11.dist-info/METADATA +0 -278
- pyproject.toml +0 -77
- /LICENSE → /jararaca-0.3.0.dist-info/LICENSE +0 -0
- {jararaca-0.2.37a11.dist-info → jararaca-0.3.0.dist-info}/entry_points.txt +0 -0
|
@@ -2,7 +2,8 @@ import inspect
|
|
|
2
2
|
from dataclasses import dataclass
|
|
3
3
|
from typing import Any, Awaitable, Callable, Generic, TypeVar, cast
|
|
4
4
|
|
|
5
|
-
from jararaca.messagebus.
|
|
5
|
+
from jararaca.messagebus.message import INHERITS_MESSAGE_CO, Message, MessageOf
|
|
6
|
+
from jararaca.scheduler.decorators import ScheduledAction
|
|
6
7
|
|
|
7
8
|
DECORATED_FUNC = TypeVar("DECORATED_FUNC", bound=Callable[..., Any])
|
|
8
9
|
DECORATED_CLASS = TypeVar("DECORATED_CLASS", bound=Any)
|
|
@@ -45,7 +46,7 @@ class MessageHandler(Generic[INHERITS_MESSAGE_CO]):
|
|
|
45
46
|
|
|
46
47
|
@staticmethod
|
|
47
48
|
def get_message_incoming(
|
|
48
|
-
func: Callable[[MessageOf[Any]], Awaitable[Any]]
|
|
49
|
+
func: Callable[[MessageOf[Any]], Awaitable[Any]],
|
|
49
50
|
) -> "MessageHandler[Message] | None":
|
|
50
51
|
if not hasattr(func, MessageHandler.MESSAGE_INCOMING_ATTR):
|
|
51
52
|
return None
|
|
@@ -62,7 +63,21 @@ class MessageHandlerData:
|
|
|
62
63
|
callable: Callable[[MessageOf[Any]], Awaitable[None]]
|
|
63
64
|
|
|
64
65
|
|
|
66
|
+
@dataclass(frozen=True)
|
|
67
|
+
class ScheduleDispatchData:
|
|
68
|
+
timestamp: float
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass(frozen=True)
|
|
72
|
+
class ScheduledActionData:
|
|
73
|
+
spec: ScheduledAction
|
|
74
|
+
callable: Callable[
|
|
75
|
+
..., Awaitable[None]
|
|
76
|
+
] # Callable[[ScheduleDispatchData], Awaitable[None]]
|
|
77
|
+
|
|
78
|
+
|
|
65
79
|
MESSAGE_HANDLER_DATA_SET = set[MessageHandlerData]
|
|
80
|
+
SCHEDULED_ACTION_DATA_SET = set[ScheduledActionData]
|
|
66
81
|
|
|
67
82
|
|
|
68
83
|
class MessageBusController:
|
|
@@ -70,11 +85,16 @@ class MessageBusController:
|
|
|
70
85
|
MESSAGEBUS_ATTR = "__messagebus__"
|
|
71
86
|
|
|
72
87
|
def __init__(self) -> None:
|
|
73
|
-
self.messagebus_factory:
|
|
88
|
+
self.messagebus_factory: (
|
|
89
|
+
Callable[[Any], tuple[MESSAGE_HANDLER_DATA_SET, SCHEDULED_ACTION_DATA_SET]]
|
|
90
|
+
| None
|
|
91
|
+
) = None
|
|
74
92
|
|
|
75
93
|
def get_messagebus_factory(
|
|
76
94
|
self,
|
|
77
|
-
) -> Callable[
|
|
95
|
+
) -> Callable[
|
|
96
|
+
[DECORATED_CLASS], tuple[MESSAGE_HANDLER_DATA_SET, SCHEDULED_ACTION_DATA_SET]
|
|
97
|
+
]:
|
|
78
98
|
if self.messagebus_factory is None:
|
|
79
99
|
raise Exception("MessageBus factory is not set")
|
|
80
100
|
return self.messagebus_factory
|
|
@@ -83,33 +103,49 @@ class MessageBusController:
|
|
|
83
103
|
|
|
84
104
|
def messagebus_factory(
|
|
85
105
|
instance: DECORATED_CLASS,
|
|
86
|
-
) -> MESSAGE_HANDLER_DATA_SET:
|
|
106
|
+
) -> tuple[MESSAGE_HANDLER_DATA_SET, SCHEDULED_ACTION_DATA_SET]:
|
|
87
107
|
handlers: MESSAGE_HANDLER_DATA_SET = set()
|
|
88
|
-
|
|
108
|
+
|
|
109
|
+
schedulers: SCHEDULED_ACTION_DATA_SET = set()
|
|
89
110
|
|
|
90
111
|
members = inspect.getmembers(func, predicate=inspect.isfunction)
|
|
91
112
|
|
|
92
113
|
for name, member in members:
|
|
93
|
-
|
|
114
|
+
message_handler_decoration = MessageHandler.get_message_incoming(member)
|
|
115
|
+
scheduled_action_decoration = ScheduledAction.get_scheduled_action(
|
|
116
|
+
member
|
|
117
|
+
)
|
|
94
118
|
|
|
95
|
-
if
|
|
96
|
-
continue
|
|
119
|
+
if message_handler_decoration is not None:
|
|
97
120
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
121
|
+
if not inspect.iscoroutinefunction(member):
|
|
122
|
+
raise Exception(
|
|
123
|
+
"Message incoming handler '%s' from '%s.%s' must be a coroutine function"
|
|
124
|
+
% (name, func.__module__, func.__qualname__)
|
|
125
|
+
)
|
|
103
126
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
127
|
+
handlers.add(
|
|
128
|
+
MessageHandlerData(
|
|
129
|
+
message_type=message_handler_decoration.message_type,
|
|
130
|
+
spec=message_handler_decoration,
|
|
131
|
+
callable=getattr(instance, name),
|
|
132
|
+
)
|
|
133
|
+
)
|
|
134
|
+
elif scheduled_action_decoration is not None:
|
|
135
|
+
if not inspect.iscoroutinefunction(member):
|
|
136
|
+
raise Exception(
|
|
137
|
+
"Scheduled action handler '%s' from '%s.%s' must be a coroutine function"
|
|
138
|
+
% (name, func.__module__, func.__qualname__)
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
schedulers.add(
|
|
142
|
+
ScheduledActionData(
|
|
143
|
+
spec=scheduled_action_decoration,
|
|
144
|
+
callable=getattr(instance, name),
|
|
145
|
+
)
|
|
109
146
|
)
|
|
110
|
-
)
|
|
111
147
|
|
|
112
|
-
return handlers
|
|
148
|
+
return handlers, schedulers
|
|
113
149
|
|
|
114
150
|
self.messagebus_factory = messagebus_factory
|
|
115
151
|
|
|
@@ -1,57 +1,72 @@
|
|
|
1
1
|
from contextlib import asynccontextmanager
|
|
2
|
-
from
|
|
2
|
+
from datetime import datetime, timedelta
|
|
3
|
+
from datetime import tzinfo as _TzInfo
|
|
4
|
+
from typing import Any, AsyncGenerator
|
|
3
5
|
|
|
4
6
|
import aio_pika
|
|
5
7
|
from aio_pika.abc import AbstractConnection
|
|
6
8
|
from pydantic import BaseModel
|
|
7
9
|
|
|
8
|
-
from jararaca.
|
|
9
|
-
from jararaca.
|
|
10
|
+
from jararaca.broker_backend import MessageBrokerBackend
|
|
11
|
+
from jararaca.messagebus.interceptors.publisher_interceptor import (
|
|
12
|
+
MessageBusConnectionFactory,
|
|
13
|
+
)
|
|
14
|
+
from jararaca.messagebus.publisher import IMessage, MessagePublisher
|
|
15
|
+
from jararaca.scheduler.types import DelayedMessageData
|
|
10
16
|
|
|
11
17
|
|
|
12
|
-
class
|
|
13
|
-
|
|
14
|
-
def provide_connection(self) -> AsyncContextManager[MessagePublisher]: ...
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class MessageBusPublisherInterceptor(AppInterceptor):
|
|
18
|
+
class AIOPikaMessagePublisher(MessagePublisher):
|
|
18
19
|
|
|
19
20
|
def __init__(
|
|
20
21
|
self,
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
channel: aio_pika.abc.AbstractChannel,
|
|
23
|
+
exchange_name: str,
|
|
24
|
+
message_broker_backend: MessageBrokerBackend | None = None,
|
|
23
25
|
):
|
|
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
26
|
|
|
40
|
-
def __init__(self, channel: aio_pika.abc.AbstractChannel, exchange_name: str):
|
|
41
27
|
self.channel = channel
|
|
42
28
|
self.exchange_name = exchange_name
|
|
29
|
+
self.message_broker_backend = message_broker_backend
|
|
43
30
|
|
|
44
|
-
async def publish(self, message:
|
|
31
|
+
async def publish(self, message: IMessage, topic: str) -> None:
|
|
45
32
|
exchange = await self.channel.declare_exchange(
|
|
46
33
|
self.exchange_name,
|
|
47
34
|
type=aio_pika.ExchangeType.TOPIC,
|
|
48
35
|
)
|
|
49
|
-
routing_key = f"{
|
|
36
|
+
routing_key = f"{topic}."
|
|
50
37
|
await exchange.publish(
|
|
51
38
|
aio_pika.Message(body=message.model_dump_json().encode()),
|
|
52
39
|
routing_key=routing_key,
|
|
53
40
|
)
|
|
54
41
|
|
|
42
|
+
async def delay(self, message: IMessage, seconds: int) -> None:
|
|
43
|
+
if not self.message_broker_backend:
|
|
44
|
+
raise NotImplementedError(
|
|
45
|
+
"Delay is not implemented for AIOPikaMessagePublisher"
|
|
46
|
+
)
|
|
47
|
+
await self.message_broker_backend.enqueue_delayed_message(
|
|
48
|
+
DelayedMessageData(
|
|
49
|
+
message_topic=message.MESSAGE_TOPIC,
|
|
50
|
+
payload=message.model_dump_json().encode(),
|
|
51
|
+
dispatch_time=int(
|
|
52
|
+
(datetime.now(tz=None) + timedelta(seconds=seconds)).timestamp()
|
|
53
|
+
),
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
async def schedule(self, message: IMessage, when: datetime, tz: _TzInfo) -> None:
|
|
58
|
+
if not self.message_broker_backend:
|
|
59
|
+
raise NotImplementedError(
|
|
60
|
+
"Schedule is not implemented for AIOPikaMessagePublisher"
|
|
61
|
+
)
|
|
62
|
+
await self.message_broker_backend.enqueue_delayed_message(
|
|
63
|
+
DelayedMessageData(
|
|
64
|
+
message_topic=message.MESSAGE_TOPIC,
|
|
65
|
+
payload=message.model_dump_json().encode(),
|
|
66
|
+
dispatch_time=int(when.timestamp()),
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
|
|
55
70
|
|
|
56
71
|
class GenericPoolConfig(BaseModel):
|
|
57
72
|
max_size: int
|
|
@@ -65,10 +80,11 @@ class AIOPikaConnectionFactory(MessageBusConnectionFactory):
|
|
|
65
80
|
exchange: str,
|
|
66
81
|
connection_pool_config: GenericPoolConfig | None = None,
|
|
67
82
|
channel_pool_config: GenericPoolConfig | None = None,
|
|
83
|
+
message_broker_backend: MessageBrokerBackend | None = None,
|
|
68
84
|
):
|
|
69
85
|
self.url = url
|
|
70
86
|
self.exchange = exchange
|
|
71
|
-
|
|
87
|
+
self.message_broker_backend = message_broker_backend
|
|
72
88
|
self.connection_pool: aio_pika.pool.Pool[AbstractConnection] | None = None
|
|
73
89
|
self.channel_pool: aio_pika.pool.Pool[aio_pika.abc.AbstractChannel] | None = (
|
|
74
90
|
None
|
|
@@ -124,7 +140,11 @@ class AIOPikaConnectionFactory(MessageBusConnectionFactory):
|
|
|
124
140
|
await tx.select()
|
|
125
141
|
|
|
126
142
|
try:
|
|
127
|
-
yield AIOPikaMessagePublisher(
|
|
143
|
+
yield AIOPikaMessagePublisher(
|
|
144
|
+
channel,
|
|
145
|
+
exchange_name=self.exchange,
|
|
146
|
+
message_broker_backend=self.message_broker_backend,
|
|
147
|
+
)
|
|
128
148
|
await tx.commit()
|
|
129
149
|
except Exception as e:
|
|
130
150
|
await tx.rollback()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from contextlib import asynccontextmanager
|
|
2
|
+
from typing import AsyncContextManager, AsyncGenerator, Protocol
|
|
3
|
+
|
|
4
|
+
from jararaca.broker_backend import MessageBrokerBackend
|
|
5
|
+
from jararaca.messagebus.publisher import MessagePublisher, provide_message_publisher
|
|
6
|
+
from jararaca.microservice import AppContext, AppInterceptor
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MessageBusConnectionFactory(Protocol):
|
|
10
|
+
|
|
11
|
+
def provide_connection(self) -> AsyncContextManager[MessagePublisher]: ...
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MessageBusPublisherInterceptor(AppInterceptor):
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
connection_factory: MessageBusConnectionFactory,
|
|
19
|
+
connection_name: str = "default",
|
|
20
|
+
message_scheduler: MessageBrokerBackend | None = None,
|
|
21
|
+
):
|
|
22
|
+
self.connection_factory = connection_factory
|
|
23
|
+
self.connection_name = connection_name
|
|
24
|
+
self.message_scheduler = message_scheduler
|
|
25
|
+
|
|
26
|
+
@asynccontextmanager
|
|
27
|
+
async def intercept(self, app_context: AppContext) -> AsyncGenerator[None, None]:
|
|
28
|
+
if app_context.context_type == "websocket":
|
|
29
|
+
yield
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
async with self.connection_factory.provide_connection() as connection:
|
|
33
|
+
with provide_message_publisher(self.connection_name, connection):
|
|
34
|
+
yield
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from datetime import datetime, tzinfo
|
|
2
|
+
from typing import Generic, Protocol, TypeVar
|
|
3
|
+
|
|
4
|
+
from jararaca.messagebus.publisher import IMessage, use_publisher
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Message(IMessage):
|
|
8
|
+
|
|
9
|
+
async def publish(self) -> None:
|
|
10
|
+
task_publisher = use_publisher()
|
|
11
|
+
await task_publisher.publish(self, self.MESSAGE_TOPIC)
|
|
12
|
+
|
|
13
|
+
async def delay(self, seconds: int) -> None:
|
|
14
|
+
task_publisher = use_publisher()
|
|
15
|
+
await task_publisher.delay(self, seconds)
|
|
16
|
+
|
|
17
|
+
async def schedule(self, when: datetime, tz: tzinfo) -> None:
|
|
18
|
+
task_publisher = use_publisher()
|
|
19
|
+
await task_publisher.schedule(self, when, tz)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
INHERITS_MESSAGE_CO = TypeVar("INHERITS_MESSAGE_CO", bound=Message, covariant=True)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class MessageOf(Protocol, Generic[INHERITS_MESSAGE_CO]):
|
|
26
|
+
|
|
27
|
+
def payload(self) -> INHERITS_MESSAGE_CO: ...
|
jararaca/messagebus/publisher.py
CHANGED
|
@@ -1,12 +1,41 @@
|
|
|
1
1
|
from contextlib import contextmanager, suppress
|
|
2
2
|
from contextvars import ContextVar
|
|
3
|
-
from
|
|
3
|
+
from datetime import datetime, tzinfo
|
|
4
|
+
from typing import Any, ClassVar, Generator, Literal, Protocol
|
|
4
5
|
|
|
5
6
|
from pydantic import BaseModel
|
|
6
7
|
|
|
7
8
|
|
|
9
|
+
class IMessage(BaseModel):
|
|
10
|
+
"""
|
|
11
|
+
Base class for messages representing tasks.
|
|
12
|
+
A Task is a message that represents a unit of work to be done.
|
|
13
|
+
It is published to a TaskPublisher and consumed by a TaskHandler, wrapped in TaskData.
|
|
14
|
+
Note: A Task is not an Event.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
MESSAGE_TOPIC: ClassVar[str] = "__unset__"
|
|
18
|
+
|
|
19
|
+
MESSAGE_TYPE: ClassVar[Literal["task", "event"]] = "task"
|
|
20
|
+
|
|
21
|
+
|
|
8
22
|
class MessagePublisher(Protocol):
|
|
9
|
-
async def publish(self, message:
|
|
23
|
+
async def publish(self, message: IMessage, topic: str) -> None:
|
|
24
|
+
raise NotImplementedError()
|
|
25
|
+
|
|
26
|
+
async def delay(self, message: IMessage, seconds: int) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Delay the message for a given number of seconds.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
raise NotImplementedError()
|
|
32
|
+
|
|
33
|
+
async def schedule(
|
|
34
|
+
self, message: IMessage, when: datetime, timezone: tzinfo
|
|
35
|
+
) -> None:
|
|
36
|
+
"""
|
|
37
|
+
Schedule the message for a given datetime.
|
|
38
|
+
"""
|
|
10
39
|
raise NotImplementedError()
|
|
11
40
|
|
|
12
41
|
|
jararaca/messagebus/worker.py
CHANGED
|
@@ -24,8 +24,9 @@ from jararaca.messagebus.decorators import (
|
|
|
24
24
|
MessageHandler,
|
|
25
25
|
MessageHandlerData,
|
|
26
26
|
)
|
|
27
|
-
from jararaca.messagebus.
|
|
27
|
+
from jararaca.messagebus.message import Message, MessageOf
|
|
28
28
|
from jararaca.microservice import MessageBusAppContext, Microservice
|
|
29
|
+
from jararaca.utils.rabbitmq_utils import RabbitmqUtils
|
|
29
30
|
|
|
30
31
|
logger = logging.getLogger(__name__)
|
|
31
32
|
|
|
@@ -33,7 +34,6 @@ logger = logging.getLogger(__name__)
|
|
|
33
34
|
@dataclass
|
|
34
35
|
class AioPikaWorkerConfig:
|
|
35
36
|
url: str
|
|
36
|
-
queue: str
|
|
37
37
|
exchange: str
|
|
38
38
|
prefetch_count: int
|
|
39
39
|
|
|
@@ -99,32 +99,28 @@ class AioPikaMicroserviceConsumer:
|
|
|
99
99
|
|
|
100
100
|
await channel.set_qos(prefetch_count=self.config.prefetch_count)
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
dlq = await channel.declare_queue("dlq")
|
|
102
|
+
main_ex = await RabbitmqUtils.declare_main_exchange(
|
|
103
|
+
channel=channel, exchange_name=self.config.exchange
|
|
104
|
+
)
|
|
107
105
|
|
|
108
|
-
await
|
|
106
|
+
dlx, dlq = await RabbitmqUtils.delcare_dl_kit(channel=channel)
|
|
109
107
|
|
|
110
108
|
for handler in self.message_handler_set:
|
|
111
109
|
|
|
112
|
-
queue_name = f"{
|
|
113
|
-
routing_key =
|
|
114
|
-
f"{self.config.exchange}.{handler.message_type.MESSAGE_TOPIC}.#"
|
|
115
|
-
)
|
|
110
|
+
queue_name = f"{handler.message_type.MESSAGE_TOPIC}.{handler.callable.__module__}.{handler.callable.__qualname__}"
|
|
111
|
+
routing_key = f"{handler.message_type.MESSAGE_TOPIC}.#"
|
|
116
112
|
|
|
117
113
|
self.incoming_map[queue_name] = handler
|
|
118
114
|
|
|
119
115
|
queue = await channel.declare_queue(
|
|
120
116
|
queue_name,
|
|
121
117
|
arguments={
|
|
122
|
-
"x-dead-letter-exchange":
|
|
123
|
-
"x-dead-letter-routing-key":
|
|
118
|
+
"x-dead-letter-exchange": dlx.name,
|
|
119
|
+
"x-dead-letter-routing-key": dlq.name,
|
|
124
120
|
},
|
|
125
121
|
)
|
|
126
122
|
|
|
127
|
-
await queue.bind(exchange=
|
|
123
|
+
await queue.bind(exchange=main_ex, routing_key=routing_key)
|
|
128
124
|
|
|
129
125
|
await queue.consume(
|
|
130
126
|
callback=MessageHandlerCallback(
|
|
@@ -205,17 +201,17 @@ class MessageHandlerCallback:
|
|
|
205
201
|
self, aio_pika_message: aio_pika.abc.AbstractIncomingMessage
|
|
206
202
|
) -> None:
|
|
207
203
|
|
|
208
|
-
|
|
204
|
+
routing_key = self.queue_name
|
|
209
205
|
|
|
210
|
-
if
|
|
206
|
+
if routing_key is None:
|
|
211
207
|
logger.warning("No topic found for message")
|
|
212
208
|
await self.handle_reject_message(aio_pika_message)
|
|
213
209
|
return
|
|
214
210
|
|
|
215
|
-
handler_data = self.consumer.incoming_map.get(
|
|
211
|
+
handler_data = self.consumer.incoming_map.get(routing_key)
|
|
216
212
|
|
|
217
213
|
if handler_data is None:
|
|
218
|
-
logger.warning("No handler found for topic '%s'" %
|
|
214
|
+
logger.warning("No handler found for topic '%s'" % routing_key)
|
|
219
215
|
await self.handle_reject_message(aio_pika_message)
|
|
220
216
|
|
|
221
217
|
return
|
|
@@ -227,7 +223,7 @@ class MessageHandlerCallback:
|
|
|
227
223
|
if len(sig.parameters) != 1:
|
|
228
224
|
logger.warning(
|
|
229
225
|
"Handler for topic '%s' must have exactly one parameter which is MessageOf[T extends Message]"
|
|
230
|
-
%
|
|
226
|
+
% routing_key
|
|
231
227
|
)
|
|
232
228
|
return
|
|
233
229
|
|
|
@@ -238,14 +234,14 @@ class MessageHandlerCallback:
|
|
|
238
234
|
if param_origin is not MessageOf:
|
|
239
235
|
logger.warning(
|
|
240
236
|
"Handler for topic '%s' must have exactly one parameter of type Message"
|
|
241
|
-
%
|
|
237
|
+
% routing_key
|
|
242
238
|
)
|
|
243
239
|
return
|
|
244
240
|
|
|
245
241
|
if len(parameter.annotation.__args__) != 1:
|
|
246
242
|
logger.warning(
|
|
247
243
|
"Handler for topic '%s' must have exactly one parameter of type Message"
|
|
248
|
-
%
|
|
244
|
+
% routing_key
|
|
249
245
|
)
|
|
250
246
|
return
|
|
251
247
|
|
|
@@ -253,8 +249,8 @@ class MessageHandlerCallback:
|
|
|
253
249
|
|
|
254
250
|
if not issubclass(message_type, BaseModel):
|
|
255
251
|
logger.warning(
|
|
256
|
-
"Handler for topic '%s' must have exactly one parameter of type
|
|
257
|
-
%
|
|
252
|
+
"Handler for topic '%s' must have exactly one parameter of type MessageOf[BaseModel]"
|
|
253
|
+
% routing_key
|
|
258
254
|
)
|
|
259
255
|
return
|
|
260
256
|
|
|
@@ -266,7 +262,7 @@ class MessageHandlerCallback:
|
|
|
266
262
|
async with self.consumer.uow_context_provider(
|
|
267
263
|
MessageBusAppContext(
|
|
268
264
|
message=builded_message,
|
|
269
|
-
topic=
|
|
265
|
+
topic=routing_key,
|
|
270
266
|
)
|
|
271
267
|
):
|
|
272
268
|
ctx: AsyncContextManager[Any]
|
|
@@ -293,7 +289,7 @@ class MessageHandlerCallback:
|
|
|
293
289
|
)
|
|
294
290
|
else:
|
|
295
291
|
logger.exception(
|
|
296
|
-
f"Error processing message on topic {
|
|
292
|
+
f"Error processing message on topic {routing_key}"
|
|
297
293
|
)
|
|
298
294
|
if incoming_message_spec.requeue_on_exception:
|
|
299
295
|
await self.handle_reject_message(aio_pika_message, requeue=True)
|
|
@@ -343,7 +339,7 @@ class MessageBusWorker:
|
|
|
343
339
|
instance: Any = self.container.get_by_type(instance_type)
|
|
344
340
|
|
|
345
341
|
factory = controller.get_messagebus_factory()
|
|
346
|
-
handlers = factory(instance)
|
|
342
|
+
handlers, _ = factory(instance)
|
|
347
343
|
|
|
348
344
|
message_handler_data_map: dict[str, MessageHandlerData] = {}
|
|
349
345
|
|