aury-boot 0.0.30__py3-none-any.whl → 0.0.32__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.
Files changed (30) hide show
  1. aury/boot/_version.py +2 -2
  2. aury/boot/application/__init__.py +2 -4
  3. aury/boot/application/app/components.py +2 -0
  4. aury/boot/application/config/settings.py +6 -0
  5. aury/boot/commands/templates/project/AGENTS.md.tpl +54 -0
  6. aury/boot/commands/templates/project/env_templates/messaging.tpl +21 -13
  7. aury/boot/commands/templates/project/env_templates/monitoring.tpl +2 -0
  8. aury/boot/infrastructure/__init__.py +4 -8
  9. aury/boot/infrastructure/channel/__init__.py +9 -8
  10. aury/boot/infrastructure/channel/backends/__init__.py +2 -6
  11. aury/boot/infrastructure/channel/backends/broadcaster.py +141 -0
  12. aury/boot/infrastructure/channel/base.py +5 -2
  13. aury/boot/infrastructure/channel/manager.py +25 -24
  14. aury/boot/infrastructure/events/__init__.py +4 -6
  15. aury/boot/infrastructure/events/backends/__init__.py +2 -4
  16. aury/boot/infrastructure/events/backends/broadcaster.py +189 -0
  17. aury/boot/infrastructure/events/base.py +9 -4
  18. aury/boot/infrastructure/events/manager.py +24 -20
  19. aury/boot/infrastructure/monitoring/alerting/manager.py +2 -0
  20. aury/boot/infrastructure/monitoring/alerting/rules.py +16 -0
  21. aury/boot/infrastructure/monitoring/tracing/processor.py +31 -1
  22. aury/boot/infrastructure/monitoring/tracing/provider.py +2 -0
  23. {aury_boot-0.0.30.dist-info → aury_boot-0.0.32.dist-info}/METADATA +4 -1
  24. {aury_boot-0.0.30.dist-info → aury_boot-0.0.32.dist-info}/RECORD +26 -28
  25. aury/boot/infrastructure/channel/backends/memory.py +0 -126
  26. aury/boot/infrastructure/channel/backends/redis.py +0 -130
  27. aury/boot/infrastructure/events/backends/memory.py +0 -86
  28. aury/boot/infrastructure/events/backends/redis.py +0 -169
  29. {aury_boot-0.0.30.dist-info → aury_boot-0.0.32.dist-info}/WHEEL +0 -0
  30. {aury_boot-0.0.30.dist-info → aury_boot-0.0.32.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,189 @@
1
+ """Broadcaster 事件总线后端。
2
+
3
+ 使用 broadcaster 库实现事件发布/订阅,支持多种后端:
4
+ - memory:// 内存(单进程)
5
+ - redis:// Redis Pub/Sub(多进程/多实例)
6
+ - kafka:// Apache Kafka
7
+ - postgres:// PostgreSQL LISTEN/NOTIFY
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import asyncio
13
+ import json
14
+
15
+ from broadcaster import Broadcast
16
+
17
+ from aury.boot.common.logging import logger
18
+
19
+ from ..base import Event, EventHandler, IEventBus
20
+
21
+ # 框架默认前缀
22
+ DEFAULT_CHANNEL_PREFIX = "aury:event:"
23
+
24
+
25
+ class BroadcasterEventBus(IEventBus):
26
+ """Broadcaster 事件总线实现。
27
+
28
+ 使用 broadcaster 库实现事件发布/订阅。
29
+
30
+ 频道命名格式:{channel_prefix}{event_name}
31
+ 默认:aury:event:user.created
32
+
33
+ 优点:
34
+ - 统一接口支持多种后端
35
+ - 内置连接池管理
36
+ - 自动重连机制
37
+ """
38
+
39
+ def __init__(
40
+ self,
41
+ url: str,
42
+ *,
43
+ channel_prefix: str = DEFAULT_CHANNEL_PREFIX,
44
+ ) -> None:
45
+ """初始化 Broadcaster 事件总线。
46
+
47
+ Args:
48
+ url: 连接 URL,格式:
49
+ - memory:// 内存(单进程)
50
+ - redis://host:port Redis Pub/Sub
51
+ - kafka://host:port Apache Kafka
52
+ - postgres://... PostgreSQL
53
+ channel_prefix: 频道名称前缀,默认 "aury:event:"
54
+
55
+ """
56
+ self._url = url
57
+ self._channel_prefix = channel_prefix
58
+ self._broadcast: Broadcast | None = None
59
+ # event_name -> list of handlers (本地订阅)
60
+ self._handlers: dict[str, list[EventHandler]] = {}
61
+ self._listener_tasks: dict[str, asyncio.Task] = {}
62
+ self._running = False
63
+
64
+ async def _ensure_connected(self) -> None:
65
+ """确保已连接。"""
66
+ if self._broadcast is None:
67
+ self._broadcast = Broadcast(self._url)
68
+ await self._broadcast.connect()
69
+ logger.debug(f"Broadcaster 事件总线已连接: {self._url}")
70
+
71
+ def _get_event_name(self, event_type: type[Event] | str) -> str:
72
+ """获取事件名称。"""
73
+ if isinstance(event_type, str):
74
+ return event_type
75
+ return event_type.__name__
76
+
77
+ def _get_channel(self, event_name: str) -> str:
78
+ """获取频道名称。"""
79
+ return f"{self._channel_prefix}{event_name}"
80
+
81
+ def subscribe(
82
+ self,
83
+ event_type: type[Event] | str,
84
+ handler: EventHandler,
85
+ ) -> None:
86
+ """订阅事件。
87
+
88
+ 注意:这是同步注册 handler,真正的监听在 start_listening() 中启动。
89
+ """
90
+ event_name = self._get_event_name(event_type)
91
+ if event_name not in self._handlers:
92
+ self._handlers[event_name] = []
93
+ if handler not in self._handlers[event_name]:
94
+ self._handlers[event_name].append(handler)
95
+ logger.debug(f"订阅事件: {event_name} -> {handler.__name__}")
96
+
97
+ # 如果已经在运行,立即为新事件启动监听
98
+ if self._running and event_name not in self._listener_tasks:
99
+ task = asyncio.create_task(self._listen_event(event_name))
100
+ self._listener_tasks[event_name] = task
101
+
102
+ def unsubscribe(
103
+ self,
104
+ event_type: type[Event] | str,
105
+ handler: EventHandler,
106
+ ) -> None:
107
+ """取消订阅事件。"""
108
+ event_name = self._get_event_name(event_type)
109
+ if event_name in self._handlers:
110
+ try:
111
+ self._handlers[event_name].remove(handler)
112
+ logger.debug(f"取消订阅事件: {event_name} -> {handler.__name__}")
113
+
114
+ # 如果该事件没有处理器了,停止监听
115
+ if not self._handlers[event_name] and event_name in self._listener_tasks:
116
+ self._listener_tasks[event_name].cancel()
117
+ del self._listener_tasks[event_name]
118
+ except ValueError:
119
+ pass
120
+
121
+ async def publish(self, event: Event) -> None:
122
+ """发布事件。"""
123
+ await self._ensure_connected()
124
+ event_name = event.event_name
125
+ channel = self._get_channel(event_name)
126
+ data = json.dumps(event.to_dict())
127
+ await self._broadcast.publish(channel=channel, message=data)
128
+
129
+ async def _listen_event(self, event_name: str) -> None:
130
+ """监听单个事件的消息。"""
131
+ channel = self._get_channel(event_name)
132
+ try:
133
+ async with self._broadcast.subscribe(channel=channel) as subscriber:
134
+ async for event_data in subscriber:
135
+ if not self._running:
136
+ break
137
+ try:
138
+ data = json.loads(event_data.message)
139
+ handlers = self._handlers.get(event_name, [])
140
+ for handler in handlers:
141
+ try:
142
+ event = Event.from_dict(data)
143
+ result = handler(event)
144
+ if asyncio.iscoroutine(result):
145
+ await result
146
+ except Exception as e:
147
+ logger.error(f"处理事件 {event_name} 失败: {e}")
148
+ except (json.JSONDecodeError, KeyError) as e:
149
+ logger.warning(f"解析事件消息失败: {e}")
150
+ except asyncio.CancelledError:
151
+ pass
152
+ except Exception as e:
153
+ logger.error(f"事件监听异常 {event_name}: {e}")
154
+
155
+ async def start_listening(self) -> None:
156
+ """开始监听事件(需要在后台任务中运行)。"""
157
+ if self._running:
158
+ return
159
+
160
+ await self._ensure_connected()
161
+ self._running = True
162
+
163
+ # 为每个已订阅的事件启动监听任务
164
+ for event_name in self._handlers:
165
+ if event_name not in self._listener_tasks:
166
+ task = asyncio.create_task(self._listen_event(event_name))
167
+ self._listener_tasks[event_name] = task
168
+
169
+ logger.debug(f"Broadcaster 事件总线开始监听,事件数: {len(self._handlers)}")
170
+
171
+ async def close(self) -> None:
172
+ """关闭事件总线。"""
173
+ self._running = False
174
+
175
+ # 取消所有监听任务
176
+ for task in self._listener_tasks.values():
177
+ task.cancel()
178
+ self._listener_tasks.clear()
179
+
180
+ # 关闭连接
181
+ if self._broadcast:
182
+ await self._broadcast.disconnect()
183
+ self._broadcast = None
184
+
185
+ self._handlers.clear()
186
+ logger.debug("Broadcaster 事件总线已关闭")
187
+
188
+
189
+ __all__ = ["BroadcasterEventBus"]
@@ -15,11 +15,16 @@ import uuid
15
15
 
16
16
 
17
17
  class EventBackend(Enum):
18
- """事件总线后端类型。"""
19
-
20
- MEMORY = "memory"
21
- REDIS = "redis"
18
+ """事件总线后端类型。
19
+
20
+ - BROADCASTER: 基于 broadcaster 库,支持 memory/redis/kafka/postgres
21
+ - RABBITMQ: 专用 RabbitMQ 实现(复杂消息场景)
22
+ - ROCKETMQ: 专用 RocketMQ 实现(预留)
23
+ """
24
+
25
+ BROADCASTER = "broadcaster"
22
26
  RABBITMQ = "rabbitmq"
27
+ ROCKETMQ = "rocketmq"
23
28
 
24
29
 
25
30
  @dataclass
@@ -10,14 +10,12 @@ from typing import TYPE_CHECKING, Any
10
10
 
11
11
  from aury.boot.common.logging import logger
12
12
 
13
- from .backends.memory import MemoryEventBus
13
+ from .backends.broadcaster import BroadcasterEventBus
14
14
  from .backends.rabbitmq import RabbitMQEventBus
15
- from .backends.redis import RedisEventBus
16
15
  from .base import Event, EventBackend, EventHandler, IEventBus
17
16
 
18
17
  if TYPE_CHECKING:
19
18
  from aury.boot.application.config import EventInstanceConfig
20
- from aury.boot.infrastructure.clients.redis import RedisClient
21
19
 
22
20
 
23
21
  class EventBusManager:
@@ -25,19 +23,19 @@ class EventBusManager:
25
23
 
26
24
  提供统一的事件总线管理接口,支持:
27
25
  - 多实例管理(如 local、distributed 各自独立)
28
- - 多后端支持(memoryredis、rabbitmq)
26
+ - 多后端支持(broadcaster、rabbitmq)
29
27
  - 发布/订阅模式
30
28
 
31
29
  使用示例:
32
30
  # 默认实例(内存)
33
31
  events = EventBusManager.get_instance()
34
- await events.initialize(backend="memory")
32
+ await events.initialize(backend="broadcaster", url="memory://")
35
33
 
36
- # 分布式实例
34
+ # 分布式实例(Redis)
37
35
  distributed = EventBusManager.get_instance("distributed")
38
36
  await distributed.initialize(
39
- backend="redis",
40
- redis_client=redis_client,
37
+ backend="broadcaster",
38
+ url="redis://localhost:6379/2",
41
39
  )
42
40
 
43
41
  # 订阅事件
@@ -92,10 +90,9 @@ class EventBusManager:
92
90
 
93
91
  async def initialize(
94
92
  self,
95
- backend: EventBackend | str = EventBackend.MEMORY,
93
+ backend: EventBackend | str = EventBackend.BROADCASTER,
96
94
  *,
97
95
  config: EventInstanceConfig | None = None,
98
- redis_client: RedisClient | None = None,
99
96
  url: str | None = None,
100
97
  channel_prefix: str | None = None,
101
98
  exchange_name: str = "aury.events",
@@ -105,9 +102,13 @@ class EventBusManager:
105
102
  Args:
106
103
  backend: 后端类型(当 config 不为 None 时忽略)
107
104
  config: Event 实例配置(推荐,自动根据 backend 初始化)
108
- redis_client: Redis 客户端(当 backend=redis 且 config=None 时需要)
109
- url: 连接 URL(当 config=None 时需要)
110
- channel_prefix: Redis 频道前缀,默认 "aury:event:"
105
+ url: 连接 URL,格式:
106
+ - memory:// 内存(单进程,默认)
107
+ - redis://host:port Redis Pub/Sub
108
+ - kafka://host:port Apache Kafka
109
+ - postgres://... PostgreSQL
110
+ - amqp://... RabbitMQ(需 backend=rabbitmq)
111
+ channel_prefix: 事件频道前缀,默认 "aury:event:"
111
112
  exchange_name: RabbitMQ 交换机名称,默认 "aury.events"
112
113
 
113
114
  Returns:
@@ -132,17 +133,20 @@ class EventBusManager:
132
133
 
133
134
  self._backend_type = backend
134
135
 
135
- # 根据后端类型创建实例,参数校验由后端自己处理
136
- if backend == EventBackend.MEMORY:
137
- self._backend = MemoryEventBus()
138
- elif backend == EventBackend.REDIS:
139
- # channel_prefix None 时使用 RedisEventBus 的默认值
140
- kwargs = {"url": url, "redis_client": redis_client}
136
+ # 根据后端类型创建实例
137
+ if backend == EventBackend.BROADCASTER:
138
+ # 默认使用内存
139
+ effective_url = url or "memory://"
140
+ kwargs: dict[str, Any] = {"url": effective_url}
141
141
  if channel_prefix is not None:
142
142
  kwargs["channel_prefix"] = channel_prefix
143
- self._backend = RedisEventBus(**kwargs)
143
+ self._backend = BroadcasterEventBus(**kwargs)
144
144
  elif backend == EventBackend.RABBITMQ:
145
+ if not url:
146
+ raise ValueError("RabbitMQ 后端需要提供 url 参数")
145
147
  self._backend = RabbitMQEventBus(url=url, exchange_name=exchange_name)
148
+ elif backend == EventBackend.ROCKETMQ:
149
+ raise NotImplementedError("RocketMQ 后端尚未实现")
146
150
  else:
147
151
  supported = ", ".join(b.value for b in EventBackend)
148
152
  raise ValueError(f"不支持的事件总线后端: {backend}。支持: {supported}")
@@ -188,6 +188,7 @@ class AlertManager:
188
188
  """创建默认规则。"""
189
189
  slow_request_threshold = self._defaults.get("slow_request_threshold", 1.0)
190
190
  slow_sql_threshold = self._defaults.get("slow_sql_threshold", 0.5)
191
+ slow_request_exclude_paths = self._defaults.get("slow_request_exclude_paths") or None
191
192
 
192
193
  default_rules = [
193
194
  # 慢请求
@@ -198,6 +199,7 @@ class AlertManager:
198
199
  aggregate_window=self._defaults.get("aggregate_window", 10),
199
200
  aggregate_threshold=self._defaults.get("slow_request_aggregate", 5),
200
201
  suppress_seconds=self._defaults.get("suppress_seconds", 300),
202
+ exclude_paths=slow_request_exclude_paths,
201
203
  ),
202
204
  # 慢 SQL
203
205
  AlertRule(
@@ -55,6 +55,7 @@ class AlertRule:
55
55
  # 过滤条件
56
56
  source_filter: str | None = None # api / task / scheduler
57
57
  path_pattern: str | None = None # 路径匹配(支持 * 通配符)
58
+ exclude_paths: list[str] | None = None # 排除路径列表(支持 * 通配符)
58
59
 
59
60
  # 聚合配置
60
61
  aggregate_window: int = 10 # 滑动窗口(秒)
@@ -66,6 +67,7 @@ class AlertRule:
66
67
 
67
68
  # 编译后的正则(内部使用)
68
69
  _path_regex: re.Pattern | None = field(default=None, repr=False)
70
+ _exclude_regexes: list[re.Pattern] = field(default_factory=list, repr=False)
69
71
 
70
72
  def __post_init__(self) -> None:
71
73
  """初始化后编译路径正则。"""
@@ -73,6 +75,12 @@ class AlertRule:
73
75
  # 将通配符转换为正则
74
76
  regex_pattern = fnmatch.translate(self.path_pattern)
75
77
  self._path_regex = re.compile(regex_pattern)
78
+
79
+ if self.exclude_paths:
80
+ # 编译所有排除路径的正则
81
+ for exclude_pattern in self.exclude_paths:
82
+ regex_pattern = fnmatch.translate(exclude_pattern)
83
+ self._exclude_regexes.append(re.compile(regex_pattern))
76
84
 
77
85
  def matches(self, event: "AlertEvent") -> bool:
78
86
  """检查事件是否匹配规则。
@@ -102,6 +110,13 @@ class AlertRule:
102
110
  if not self._path_regex.match(endpoint):
103
111
  return False
104
112
 
113
+ # 检查排除路径
114
+ if self._exclude_regexes:
115
+ endpoint = event.metadata.get("endpoint", "")
116
+ for exclude_regex in self._exclude_regexes:
117
+ if exclude_regex.match(endpoint):
118
+ return False # 匹配到排除规则,不触发告警
119
+
105
120
  # 检查阈值(对于 slow_* 类型)
106
121
  if self.threshold is not None and event.event_type in (
107
122
  AlertEventType.SLOW_REQUEST,
@@ -147,6 +162,7 @@ def load_rules_from_dict(data: dict) -> tuple[dict, list[AlertRule]]:
147
162
  severity_min=severity_min,
148
163
  source_filter=rule_data.get("source_filter") or rule_data.get("source"),
149
164
  path_pattern=rule_data.get("path_pattern"),
165
+ exclude_paths=rule_data.get("exclude_paths"),
150
166
  aggregate_window=rule_data.get("aggregate_window", defaults.get("aggregate_window", 10)),
151
167
  aggregate_threshold=rule_data.get("aggregate_threshold", defaults.get("aggregate_threshold", 1)),
152
168
  suppress_seconds=rule_data.get("suppress_seconds", defaults.get("suppress_seconds", 300)),
@@ -4,6 +4,8 @@ from __future__ import annotations
4
4
 
5
5
  import asyncio
6
6
  from collections.abc import Awaitable, Callable
7
+ import fnmatch
8
+ import re
7
9
  from typing import TYPE_CHECKING, Any
8
10
 
9
11
  from aury.boot.common.logging import logger
@@ -49,6 +51,7 @@ class AlertingSpanProcessor:
49
51
  alert_on_slow_sql: bool = True,
50
52
  alert_on_error: bool = True,
51
53
  alert_callback: AlertCallback | None = None,
54
+ slow_request_exclude_paths: list[str] | None = None,
52
55
  ) -> None:
53
56
  """初始化 AlertingSpanProcessor。
54
57
 
@@ -59,6 +62,7 @@ class AlertingSpanProcessor:
59
62
  alert_on_slow_sql: 是否对慢 SQL 发送告警
60
63
  alert_on_error: 是否对异常 span 发送告警
61
64
  alert_callback: 告警回调函数,签名: async (event_type, message, **metadata) -> None
65
+ slow_request_exclude_paths: 慢请求排除路径列表(支持 * 通配符),如 SSE/WebSocket 长连接
62
66
  """
63
67
  self._slow_request_threshold = slow_request_threshold
64
68
  self._slow_sql_threshold = slow_sql_threshold
@@ -66,6 +70,13 @@ class AlertingSpanProcessor:
66
70
  self._alert_on_slow_sql = alert_on_slow_sql
67
71
  self._alert_on_error = alert_on_error
68
72
  self._alert_callback = alert_callback
73
+
74
+ # 编译排除路径正则
75
+ self._exclude_regexes: list[re.Pattern] = []
76
+ if slow_request_exclude_paths:
77
+ for pattern in slow_request_exclude_paths:
78
+ regex_pattern = fnmatch.translate(pattern)
79
+ self._exclude_regexes.append(re.compile(regex_pattern))
69
80
 
70
81
  def on_start(self, span: "Span", parent_context: object = None) -> None:
71
82
  """span 开始时调用(不做处理)。"""
@@ -95,6 +106,10 @@ class AlertingSpanProcessor:
95
106
 
96
107
  # 检测慢 span
97
108
  if should_alert and threshold > 0 and duration_s >= threshold:
109
+ # 检查是否在排除路径中
110
+ if self._is_path_excluded(name, attributes):
111
+ return
112
+
98
113
  self._emit_slow_alert(
99
114
  name=name,
100
115
  duration=duration_s,
@@ -149,11 +164,25 @@ class AlertingSpanProcessor:
149
164
  """根据 span 类型判断是否应该发送慢告警。"""
150
165
  if span_kind == "database":
151
166
  return self._alert_on_slow_sql
152
- elif span_kind in ("http", "http_client"):
167
+ elif span_kind in ("http", "http_client", "internal"):
153
168
  return self._alert_on_slow_request
154
169
  # 其他类型默认使用 HTTP 的开关
155
170
  return self._alert_on_slow_request
156
171
 
172
+ def _is_path_excluded(self, name: str, attributes: dict) -> bool:
173
+ """检查路径是否在排除列表中。"""
174
+ if not self._exclude_regexes:
175
+ return False
176
+
177
+ # 从 attributes 或 span name 中提取路径
178
+ path = (
179
+ attributes.get("http.route")
180
+ or attributes.get("http.target")
181
+ or name
182
+ )
183
+
184
+ return any(regex.match(path) for regex in self._exclude_regexes)
185
+
157
186
  def _emit_slow_alert(
158
187
  self,
159
188
  name: str,
@@ -260,6 +289,7 @@ def _get_event_type_for_slow(span_kind: str) -> str:
260
289
  "http": "slow_request",
261
290
  "database": "slow_sql",
262
291
  "http_client": "slow_request",
292
+ "internal": "slow_request", # internal span 也用 slow_request 类型
263
293
  }
264
294
  return mapping.get(span_kind, "custom")
265
295
 
@@ -81,6 +81,7 @@ class TelemetryConfig:
81
81
  alert_on_slow_sql: bool = True # 是否对慢 SQL 发送告警
82
82
  alert_on_error: bool = True
83
83
  alert_callback: Any = None # 告警回调函数
84
+ slow_request_exclude_paths: list[str] = field(default_factory=list) # 慢请求排除路径
84
85
 
85
86
  # OTLP Traces 导出配置
86
87
  traces_endpoint: str | None = None
@@ -181,6 +182,7 @@ class TelemetryProvider:
181
182
  alert_on_slow_sql=self._config.alert_on_slow_sql,
182
183
  alert_on_error=self._config.alert_on_error,
183
184
  alert_callback=self._config.alert_callback,
185
+ slow_request_exclude_paths=self._config.slow_request_exclude_paths or None,
184
186
  )
185
187
  self._provider.add_span_processor(alerting_processor)
186
188
  logger.debug("已添加 AlertingSpanProcessor")
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aury-boot
3
- Version: 0.0.30
3
+ Version: 0.0.32
4
4
  Summary: Aury Boot - 基于 FastAPI 生态的企业级 API 开发框架
5
5
  Requires-Python: >=3.13
6
6
  Requires-Dist: alembic>=1.17.2
7
7
  Requires-Dist: aury-sdk-storage[aws]>=0.0.6
8
8
  Requires-Dist: babel>=2.17.0
9
+ Requires-Dist: broadcaster[redis]>=0.3.1
9
10
  Requires-Dist: faker>=38.2.0
10
11
  Requires-Dist: fastapi>=0.122.0
11
12
  Requires-Dist: greenlet>=3.2.4
@@ -30,6 +31,8 @@ Requires-Dist: aury-sdk-storage[aws]>=0.0.1; extra == 'all'
30
31
  Requires-Dist: dramatiq>=1.18.0; extra == 'all'
31
32
  Requires-Dist: pika>=1.3.2; extra == 'all'
32
33
  Requires-Dist: redis>=7.1.0; extra == 'all'
34
+ Provides-Extra: broadcaster
35
+ Requires-Dist: broadcaster[redis]>=0.3.1; extra == 'broadcaster'
33
36
  Provides-Extra: dev
34
37
  Requires-Dist: mypy>=1.19.0; extra == 'dev'
35
38
  Requires-Dist: pytest-asyncio>=1.3.0; extra == 'dev'
@@ -1,6 +1,6 @@
1
1
  aury/boot/__init__.py,sha256=pCno-EInnpIBa1OtxNYF-JWf9j95Cd2h6vmu0xqa_-4,1791
2
- aury/boot/_version.py,sha256=od6_NordEIvGqyI_S2FZ1DYZPTNZflFSs-zacl-pIks,706
3
- aury/boot/application/__init__.py,sha256=0o_XmiwFCeAu06VHggS8I1e7_nSMoRq0Hcm0fYfCywU,3071
2
+ aury/boot/_version.py,sha256=R_6iGx2TpbHTm0_3hIB8Kl5225iMZqRsqf47DXFHa64,706
3
+ aury/boot/application/__init__.py,sha256=I2KqNVdYg2q5nlOXr0TtFGyHmhj4oWdaR6ZB73Mwg7Y,3041
4
4
  aury/boot/application/adapter/__init__.py,sha256=e1bcSb1bxUMfofTwiCuHBZJk5-STkMCWPF2EJXHQ7UU,3976
5
5
  aury/boot/application/adapter/base.py,sha256=Ar_66fiHPDEmV-1DKnqXKwc53p3pozG31bgTJTEUriY,15763
6
6
  aury/boot/application/adapter/config.py,sha256=X6ppQMldyJbEdG1GcQSc2SulLtyeBTr8OAboYIjkSu0,8153
@@ -9,12 +9,12 @@ aury/boot/application/adapter/exceptions.py,sha256=Kzm-ytRxdUnSMIcWCSOHPxo4Jh_A6
9
9
  aury/boot/application/adapter/http.py,sha256=4TADsSzdSRU63307dmmo-2U_JpVP12mwTFy66B5Ps-w,10759
10
10
  aury/boot/application/app/__init__.py,sha256=I8FfCKDuDQsGzAK6BevyfdtAwieMUVYu6qgVQzBazpE,830
11
11
  aury/boot/application/app/base.py,sha256=7n7uFAVmIylr9YZannWKeQSOLSifNosIJUMbL-nmJe4,21897
12
- aury/boot/application/app/components.py,sha256=p_OA0sIy65sKgVLZWurxHygEzG3g4wDfGg8F3A7i6VY,33294
12
+ aury/boot/application/app/components.py,sha256=Ub7NlfxSPXSDcxUajQ5ed42kNmsBSol-UttcBfnx64Y,33473
13
13
  aury/boot/application/app/middlewares.py,sha256=BXe2H14FHzJUVpQM6DZUm-zfZRXSXIi1QIZ4_3izfHw,3306
14
14
  aury/boot/application/app/startup.py,sha256=DHKt3C2G7V5XfFr1SQMl14tNzcuDd9MqUVAxi274HDQ,7873
15
15
  aury/boot/application/config/__init__.py,sha256=Dd-myRSBCM18DXXsi863h0cJG5VFrI10xMRtjnvelGo,1894
16
16
  aury/boot/application/config/multi_instance.py,sha256=RXSp-xP8-bKMDEhq3SeL7T3lS8-vpRlvBEVBuZVjVK4,6475
17
- aury/boot/application/config/settings.py,sha256=NoYmacyjXMkOHA1-OVj5XTu_ZzKqGqsKRmQ0YUz3hes,37621
17
+ aury/boot/application/config/settings.py,sha256=MPOjUyPxvWOrw878FOs0gnUPkqSUMyLpQ-MZz9yMwls,37866
18
18
  aury/boot/application/constants/__init__.py,sha256=DCXs13_VVaQWHqO-qpJoZwRd7HIexiirtw_nu8msTXE,340
19
19
  aury/boot/application/constants/components.py,sha256=I4SlsF2DpSzMiLsi1wVrEmdHn4yV5J2h3ikMQqufPmM,1120
20
20
  aury/boot/application/constants/scheduler.py,sha256=S77FBIvHlyruvlabRWZJ2J1YAs2xWXPQI2yuGdGUDNA,471
@@ -61,7 +61,7 @@ aury/boot/commands/templates/generate/model.py.tpl,sha256=knFwMyGZ7wMpzH4_bQD_V1
61
61
  aury/boot/commands/templates/generate/repository.py.tpl,sha256=xoEg6lPAaLIRDeFy4I0FBsPPVLSy91h6xosAlaCL_mM,590
62
62
  aury/boot/commands/templates/generate/schema.py.tpl,sha256=HIaY5B0UG_S188nQLrZDEJ0q73WPdb7BmCdc0tseZA4,545
63
63
  aury/boot/commands/templates/generate/service.py.tpl,sha256=2hwQ8e4a5d_bIMx_jGDobdmKPMFLBlfQrQVQH4Ym5k4,1842
64
- aury/boot/commands/templates/project/AGENTS.md.tpl,sha256=IWMtEqabtI0n_Mj0oBpIIblvZqF2AWRcZ_loByozMHA,8528
64
+ aury/boot/commands/templates/project/AGENTS.md.tpl,sha256=sp5qyzU-SGhgQCobpMW4EXRzpGsEsVdmJvspnKAP4AQ,10059
65
65
  aury/boot/commands/templates/project/README.md.tpl,sha256=oCeBiukk6Pa3hrCKybkfM2sIRHsPZ15nlwuFTUSFDwY,2459
66
66
  aury/boot/commands/templates/project/admin_console_init.py.tpl,sha256=K81L14thyEhRA8lFCQJVZL_NU22-sBz0xS68MJPeoCo,1541
67
67
  aury/boot/commands/templates/project/alert_rules.example.yaml.tpl,sha256=QZH6SC5TcUhgX_2JRXk0k0g26wJf9xNwsdquiEIgg-I,2492
@@ -93,8 +93,8 @@ aury/boot/commands/templates/project/env_templates/admin.tpl,sha256=wWt3iybOpBHt
93
93
  aury/boot/commands/templates/project/env_templates/cache.tpl,sha256=_sK-p_FECj4mVvggNvgb4Wu0yGii0Ocz560syG7DU2c,498
94
94
  aury/boot/commands/templates/project/env_templates/database.tpl,sha256=2lWzTKt4X0SpeBBCkrDV90Di4EfoAuqYzhVsh74vTUI,907
95
95
  aury/boot/commands/templates/project/env_templates/log.tpl,sha256=x5rkrEFJISH0gaCcr-wTCbDYtyFnlLNJpY789fqjZgc,754
96
- aury/boot/commands/templates/project/env_templates/messaging.tpl,sha256=ZaNBM4pq0pgkTXbCBx_sgjm8QKEBfW1nSnsKZfHu-HM,1771
97
- aury/boot/commands/templates/project/env_templates/monitoring.tpl,sha256=02I4pxCkSbHaBeD9a7BN7YhecH2f2s3yY0Ufi2lMyaE,2429
96
+ aury/boot/commands/templates/project/env_templates/messaging.tpl,sha256=SzPRKwN0wO5e1kpjkSwpPJfVmiUDzZkK4Qm-qNsCvVE,2178
97
+ aury/boot/commands/templates/project/env_templates/monitoring.tpl,sha256=Zq0xQzDrCRtbeLCQB3pkEE2p8FFED6IjQo4TqMyd_P8,2584
98
98
  aury/boot/commands/templates/project/env_templates/rpc.tpl,sha256=FhweCFakawGLSs01a_BkmZo11UhWax2-VCBudHj68WA,1163
99
99
  aury/boot/commands/templates/project/env_templates/scheduler.tpl,sha256=c8Grcs1rgBB58RHlxqmDMPHQl8BnbcqNW473ctmsojU,752
100
100
  aury/boot/commands/templates/project/env_templates/service.tpl,sha256=b-a2GyRyoaunbDj_2kaSw3OFxcugscmPvUBG7w0XO8c,710
@@ -134,19 +134,18 @@ aury/boot/domain/repository/query_builder.py,sha256=pFErMzsBql-T6gBX0S4FxIheCkNa
134
134
  aury/boot/domain/service/__init__.py,sha256=ZRotaBlqJXn7ebPTQjjoHtorpQREk8AgTD69UCcRd1k,118
135
135
  aury/boot/domain/service/base.py,sha256=6sN0nf8r5yUZsE6AcZOiOXFCqzb61oCxTfrWlqjIo9I,2035
136
136
  aury/boot/domain/transaction/__init__.py,sha256=EKnjJ235SYjMCvGIuLVlTdYRzU35RxNMejRGUExYqqE,15488
137
- aury/boot/infrastructure/__init__.py,sha256=ppP1-suaDICMNvBSXj_4DVSH3h0D8e0qZhtENCr16m8,3007
137
+ aury/boot/infrastructure/__init__.py,sha256=DDEr_BIL5OyMJjNlI05jGIUrSHn6MPdnW9xnCS4eHfg,2949
138
138
  aury/boot/infrastructure/cache/__init__.py,sha256=G40uCkpJ1jSs2fc_CBDem73iQQzCcp-4GG1WpDJzwaA,658
139
139
  aury/boot/infrastructure/cache/backends.py,sha256=9QMQ8G9DtZgzVXZ_Ng7n1gXRu-_OQZgw4FHPOfr1qco,13585
140
140
  aury/boot/infrastructure/cache/base.py,sha256=Yn-h_SGcOoGGZW1unOnz_zgcuHaMKOEmwiUP0P7_pIM,1624
141
141
  aury/boot/infrastructure/cache/exceptions.py,sha256=KZsFIHXW3_kOh_KB93EVZJKbiDvDw8aloAefJ3kasP8,622
142
142
  aury/boot/infrastructure/cache/factory.py,sha256=aF74JoiiSKFgctqqh2Z8OtGRS2Am_ou-I40GyygLzC0,2489
143
143
  aury/boot/infrastructure/cache/manager.py,sha256=GGoOgYyIdWKMmhej5cRvEfpNeMN1GaSaU9hc0dy8_sA,12106
144
- aury/boot/infrastructure/channel/__init__.py,sha256=Ztcfn1-TomgV91qhePpFK-3_nKgBt862yEFYUzIwPlo,566
145
- aury/boot/infrastructure/channel/base.py,sha256=FRFHzjDDLHqVSzpjGiPM15BSSVEihRMHBtja74vkRYM,2782
146
- aury/boot/infrastructure/channel/manager.py,sha256=wOkO018Ch2694z9vOGgojaGOdCXHi0zrekkfLezn8bo,7444
147
- aury/boot/infrastructure/channel/backends/__init__.py,sha256=zrOhrzkhEIgsO7Armhgda1ruJQ6a9ZK7GPZuzvEiuN8,151
148
- aury/boot/infrastructure/channel/backends/memory.py,sha256=QQyZxIdYtA_pWqdKgUIMkvnbBwvv45-vX-qostDHyfg,4699
149
- aury/boot/infrastructure/channel/backends/redis.py,sha256=_UL7wE-bO147CPXKDjJgYGjj09Lg9x9U2PLYa37q5yQ,4666
144
+ aury/boot/infrastructure/channel/__init__.py,sha256=NmjddenZPz1Dcl0glwIF1Xn9gxBzvGvlOlzhV3eEnEQ,664
145
+ aury/boot/infrastructure/channel/base.py,sha256=TDiP7pXyd2ixiOM3cbxqCSOluGLTkmLCa8pv-KyQ0jo,2941
146
+ aury/boot/infrastructure/channel/manager.py,sha256=GT6eG6PglduKAr23i1PSmjjTQsALvGGoLjYiQ33aZiw,7488
147
+ aury/boot/infrastructure/channel/backends/__init__.py,sha256=NcXG8_KAqy1SiGUs2z_KvkS90jMfLJ6bzyYK4Jw4qCg,107
148
+ aury/boot/infrastructure/channel/backends/broadcaster.py,sha256=y8eKx6X6Iy9a_5vnLMm5gjqkq05SmJEWESw1-x0lIFg,4771
150
149
  aury/boot/infrastructure/clients/__init__.py,sha256=1ANMejb3RrBgaR-jq-dsxJ0kQDRHz5jV-QvdUNcf_ok,435
151
150
  aury/boot/infrastructure/clients/rabbitmq/__init__.py,sha256=cnU-W7jOcAgp_FvsY9EipNCeJzeA9gHLRuZ0yQZE2DI,200
152
151
  aury/boot/infrastructure/clients/rabbitmq/config.py,sha256=YmvNiISpqNt-LE2CrpzmxCgaEgYna7IbOfUSnA0B4T0,1239
@@ -162,20 +161,19 @@ aury/boot/infrastructure/database/query_tools/__init__.py,sha256=pOFuyDDNpkY5cSM
162
161
  aury/boot/infrastructure/database/strategies/__init__.py,sha256=foj_2xEsgLZxshpK65YAhdJ2UZyh1tKvGRq6sre8pQY,5909
163
162
  aury/boot/infrastructure/di/__init__.py,sha256=qFYlk265d6_rS8OiX37_wOc7mBFw8hk3yipDYNkyjQg,231
164
163
  aury/boot/infrastructure/di/container.py,sha256=14FVbafGXea-JEAYeOEBxB6zAwndLCZJvprKiD_1IOQ,12524
165
- aury/boot/infrastructure/events/__init__.py,sha256=D5JNFkGHCH79nYbqUil0Z8eW2p6Gx8P0vBbNnHqnTgM,698
166
- aury/boot/infrastructure/events/base.py,sha256=oS6aNUWRvpXlbh7L3_4vzlwUumYmg44HKS1S4m_zOFo,3019
167
- aury/boot/infrastructure/events/manager.py,sha256=Hnua9x_Ppmo99JUEmjuZcKIPv2IEZQ3Du9ziPg-C8Fo,7570
164
+ aury/boot/infrastructure/events/__init__.py,sha256=-fXZiTKkwh2olyw8BCGO-Qv67ZDCS0enioY005vPhrI,676
165
+ aury/boot/infrastructure/events/base.py,sha256=m5sXe7rpdvq6pcgCAn2PX7lLXZgCpujteRqHXQ0oaqs,3238
166
+ aury/boot/infrastructure/events/manager.py,sha256=aQNzyPuz1oWAMkXz4UQqCRSPiGTcm8HmSE1lGWovhWE,7754
168
167
  aury/boot/infrastructure/events/middleware.py,sha256=Ck3qNMTtLuFFKsJuEUeOMG9nu3qK1N_aqt6wH5JoAtw,1336
169
- aury/boot/infrastructure/events/backends/__init__.py,sha256=V_hPtdjVUkYU4Uf8hTPVBUcnNYG9OfkjRPDnjp_5_zA,224
170
- aury/boot/infrastructure/events/backends/memory.py,sha256=Up7vAxdJvIqkcqpnKNCu81ec6iCfNIhcQ-jKM3M2hZc,2623
168
+ aury/boot/infrastructure/events/backends/__init__.py,sha256=1mj0rDauHdoRm4kXOg87l2f9jnMbj_jKZdVnIZMj9XM,185
169
+ aury/boot/infrastructure/events/backends/broadcaster.py,sha256=FnxO62LUXWLs1ZEiaYmNiMaL3ccXNtuc3DFzLe02eK0,6700
171
170
  aury/boot/infrastructure/events/backends/rabbitmq.py,sha256=XCuI9mc3GR-t0zht4yZ3e2nnyFl8UuTDir_0nsDbfxM,6495
172
- aury/boot/infrastructure/events/backends/redis.py,sha256=i8jPCtR7ITPVTl9DVFDbNbjypnWoeSpar6z4lJJlOD8,5790
173
171
  aury/boot/infrastructure/monitoring/__init__.py,sha256=KGtJU0slbRvFzzUv60LQHB12sX7eNNvGDu8Lyk9Owy8,22415
174
172
  aury/boot/infrastructure/monitoring/alerting/__init__.py,sha256=gBZ23JnCjqglyYTTUxfkmilZ4mY_ZkrkKMDo--3COGE,1363
175
173
  aury/boot/infrastructure/monitoring/alerting/aggregator.py,sha256=fiI-lBSqWxXv1eVPfaDNjcigX-81w41fcmhD_vN_XSs,5805
176
174
  aury/boot/infrastructure/monitoring/alerting/events.py,sha256=zJvTevQ-9JflIDyYVo1BRzOVyAGhdgEfRlMsD0NcBgM,4056
177
- aury/boot/infrastructure/monitoring/alerting/manager.py,sha256=7QWQ_epf3b8Y3SkJ08RI6pAf0OFmX_Apm8znV93wYQY,14373
178
- aury/boot/infrastructure/monitoring/alerting/rules.py,sha256=sNj0uKsfioq64aWx3eRGZjqY-dJKNzTCxAkpf0cSHzc,5294
175
+ aury/boot/infrastructure/monitoring/alerting/manager.py,sha256=ZcIMhBgHmrSGn8FeJOIBIiwKOcdWvT6NBm-6wvRmGc4,14525
176
+ aury/boot/infrastructure/monitoring/alerting/rules.py,sha256=XcXJXWVrPpdZKKz63BiVWmwkKitIaNQWBfJATrSzG1M,6116
179
177
  aury/boot/infrastructure/monitoring/alerting/notifiers/__init__.py,sha256=dsfxThPHO_Ofb3Wo_dYlL8HvP_N63pb_S_UXm_qSxF8,321
180
178
  aury/boot/infrastructure/monitoring/alerting/notifiers/base.py,sha256=_RXZMzWX-YeTG0Up1U8CwK8ADfX34dd0Sh56ugfqOWM,1462
181
179
  aury/boot/infrastructure/monitoring/alerting/notifiers/feishu.py,sha256=JAMJiCNRYoDeJrYn29ew_ZVXDGq8OLgiFApRWd4iPY0,7134
@@ -184,8 +182,8 @@ aury/boot/infrastructure/monitoring/health/__init__.py,sha256=nqwFFXl6J9yTfQa1JL
184
182
  aury/boot/infrastructure/monitoring/tracing/__init__.py,sha256=YizkpnhY-bcUUcd8YaDzUsluMflhNOH1dAKdVtkW05U,1287
185
183
  aury/boot/infrastructure/monitoring/tracing/context.py,sha256=s_k2MzNl4LDDpei9xUP6TFW5BwZneoQg44RPaw95jac,978
186
184
  aury/boot/infrastructure/monitoring/tracing/logging.py,sha256=gzuKa1ZiyY4z06fHNTbjgZasS6mLftSEaZQQ-Z6J_RE,2041
187
- aury/boot/infrastructure/monitoring/tracing/processor.py,sha256=rzsFbs05acj_CGH4yFSYYR1yxV9cJasxBIBoS3bAONE,11409
188
- aury/boot/infrastructure/monitoring/tracing/provider.py,sha256=b12lVkQvypI3sPDkj14z9Tlup6UMpitZRLoKObL-Lg4,11364
185
+ aury/boot/infrastructure/monitoring/tracing/processor.py,sha256=qc37YmS8rslpwqAYHrBDzVvNWmXRIFEwpld34NMmByk,12640
186
+ aury/boot/infrastructure/monitoring/tracing/provider.py,sha256=AnPHUDHnfrCB48WHjp9vLBhCh9BpyfWb3DHGRh6Din4,11553
189
187
  aury/boot/infrastructure/monitoring/tracing/tracing.py,sha256=BeWL-FYtlQ05r05wGJ6qjTSpypgCp-7OzdNnZ3uunB0,6890
190
188
  aury/boot/infrastructure/mq/__init__.py,sha256=Q7kBk_GeQnxnqkyp29Bh1yFH3Q8xxxjs8oDYLeDj8C0,498
191
189
  aury/boot/infrastructure/mq/base.py,sha256=kHrWUysWflMj3qyOnioLZ90it8d9Alq1Wb4PYhpBW4k,3396
@@ -211,7 +209,7 @@ aury/boot/testing/client.py,sha256=KOg1EemuIVsBG68G5y0DjSxZGcIQVdWQ4ASaHE3o1R0,4
211
209
  aury/boot/testing/factory.py,sha256=8GvwX9qIDu0L65gzJMlrWB0xbmJ-7zPHuwk3eECULcg,5185
212
210
  aury/boot/toolkit/__init__.py,sha256=AcyVb9fDf3CaEmJPNkWC4iGv32qCPyk4BuFKSuNiJRQ,334
213
211
  aury/boot/toolkit/http/__init__.py,sha256=zIPmpIZ9Qbqe25VmEr7jixoY2fkRbLm7NkCB9vKpg6I,11039
214
- aury_boot-0.0.30.dist-info/METADATA,sha256=5vGoIS2-MUEahzRGkZcOX8xeTDYXKTGKm-gV4x7qpJY,8560
215
- aury_boot-0.0.30.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
216
- aury_boot-0.0.30.dist-info/entry_points.txt,sha256=f9KXEkDIGc0BGkgBvsNx_HMz9VhDjNxu26q00jUpDwQ,49
217
- aury_boot-0.0.30.dist-info/RECORD,,
212
+ aury_boot-0.0.32.dist-info/METADATA,sha256=QlqZSaFqARK6vxLILTJn6BKGKBHejKRtO085_XZK2BE,8694
213
+ aury_boot-0.0.32.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
214
+ aury_boot-0.0.32.dist-info/entry_points.txt,sha256=f9KXEkDIGc0BGkgBvsNx_HMz9VhDjNxu26q00jUpDwQ,49
215
+ aury_boot-0.0.32.dist-info/RECORD,,