aury-boot 0.0.39__py3-none-any.whl → 0.0.40__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.
@@ -7,14 +7,18 @@
7
7
  - 超时控制
8
8
  - 错误处理
9
9
  - 请求日志
10
+
11
+ 基于 aiohttp 实现,全异步无阻塞。
10
12
  """
11
13
 
12
14
  from __future__ import annotations
13
15
 
16
+ import time
14
17
  from abc import ABC, abstractmethod
15
- from typing import Any, Optional, TypeVar
18
+ from dataclasses import dataclass, field
19
+ from typing import Any, TypeVar
16
20
 
17
- import httpx
21
+ import aiohttp
18
22
  from pydantic import BaseModel
19
23
  from tenacity import (
20
24
  retry,
@@ -35,7 +39,6 @@ class RetryConfig(BaseModel):
35
39
  retry_delay: float = 1.0
36
40
  backoff_factor: float = 2.0
37
41
  retry_on_status: list[int] = [500, 502, 503, 504]
38
- retry_on_exceptions: tuple = (httpx.TimeoutException, httpx.NetworkError)
39
42
 
40
43
 
41
44
  class HttpClientConfig(BaseModel):
@@ -50,16 +53,83 @@ class HttpClientConfig(BaseModel):
50
53
  retry: RetryConfig | None = None
51
54
 
52
55
 
56
+ @dataclass
57
+ class HttpRequest:
58
+ """请求对象(用于拦截器)。"""
59
+
60
+ method: str
61
+ url: str
62
+ headers: dict[str, str] = field(default_factory=dict)
63
+ params: dict[str, Any] | None = None
64
+ json_data: Any = None
65
+ data: Any = None
66
+
67
+
68
+ @dataclass
69
+ class HttpResponse:
70
+ """响应对象(用于拦截器和返回)。"""
71
+
72
+ status_code: int
73
+ url: str
74
+ headers: dict[str, str]
75
+ text: str
76
+ content: bytes
77
+ elapsed_seconds: float
78
+
79
+ def json(self) -> Any:
80
+ """解析 JSON 响应。"""
81
+ import json
82
+ return json.loads(self.text)
83
+
84
+ @property
85
+ def is_success(self) -> bool:
86
+ """是否成功响应。"""
87
+ return 200 <= self.status_code < 400
88
+
89
+ def raise_for_status(self) -> None:
90
+ """如果状态码表示错误,抛出异常。"""
91
+ if self.status_code >= 400:
92
+ raise HttpStatusError(
93
+ f"HTTP {self.status_code}",
94
+ status_code=self.status_code,
95
+ response=self,
96
+ )
97
+
98
+
99
+ class HttpError(Exception):
100
+ """HTTP 错误基类。"""
101
+ pass
102
+
103
+
104
+ class HttpStatusError(HttpError):
105
+ """HTTP 状态码错误。"""
106
+
107
+ def __init__(self, message: str, status_code: int, response: HttpResponse) -> None:
108
+ super().__init__(message)
109
+ self.status_code = status_code
110
+ self.response = response
111
+
112
+
113
+ class HttpTimeoutError(HttpError):
114
+ """HTTP 超时错误。"""
115
+ pass
116
+
117
+
118
+ class HttpNetworkError(HttpError):
119
+ """HTTP 网络错误。"""
120
+ pass
121
+
122
+
53
123
  class RequestInterceptor(ABC):
54
124
  """请求拦截器接口。"""
55
125
 
56
126
  @abstractmethod
57
- async def before_request(self, request: httpx.Request) -> httpx.Request:
127
+ async def before_request(self, request: HttpRequest) -> HttpRequest:
58
128
  """请求前处理。"""
59
129
  pass
60
130
 
61
131
  @abstractmethod
62
- async def after_response(self, response: httpx.Response) -> httpx.Response:
132
+ async def after_response(self, response: HttpResponse) -> HttpResponse:
63
133
  """响应后处理。"""
64
134
  pass
65
135
 
@@ -67,25 +137,25 @@ class RequestInterceptor(ABC):
67
137
  class LoggingInterceptor(RequestInterceptor):
68
138
  """日志拦截器。"""
69
139
 
70
- async def before_request(self, request: httpx.Request) -> httpx.Request:
140
+ async def before_request(self, request: HttpRequest) -> HttpRequest:
71
141
  """记录请求日志。"""
72
142
  logger.debug(
73
143
  f"HTTP请求: {request.method} {request.url} | "
74
- f"Headers: {dict(request.headers)}"
144
+ f"Headers: {request.headers}"
75
145
  )
76
146
  return request
77
147
 
78
- async def after_response(self, response: httpx.Response) -> httpx.Response:
148
+ async def after_response(self, response: HttpResponse) -> HttpResponse:
79
149
  """记录响应日志。"""
80
150
  logger.debug(
81
151
  f"HTTP响应: {response.status_code} {response.url} | "
82
- f"耗时: {response.elapsed.total_seconds():.3f}s"
152
+ f"耗时: {response.elapsed_seconds:.3f}s"
83
153
  )
84
154
  return response
85
155
 
86
156
 
87
157
  class HttpClient:
88
- """企业级HTTP客户端。
158
+ """企业级HTTP客户端(基于 aiohttp)。
89
159
 
90
160
  特性:
91
161
  - 连接池管理
@@ -93,6 +163,7 @@ class HttpClient:
93
163
  - 拦截器支持
94
164
  - 超时控制
95
165
  - 错误处理
166
+ - 全异步无阻塞
96
167
 
97
168
  使用示例:
98
169
  # 基础使用
@@ -125,33 +196,39 @@ class HttpClient:
125
196
  Args:
126
197
  base_url: 基础URL
127
198
  timeout: 超时时间(秒)
128
- follow_redirects: 是否跟随重定向
199
+ follow_redirects: 是否跟随重定向(aiohttp 默认不跟随)
129
200
  max_connections: 最大连接数
130
201
  retry_config: 重试配置
131
202
  """
132
- self._base_url = base_url
133
- self._timeout = timeout
203
+ self._base_url = base_url.rstrip("/") if base_url else ""
204
+ self._timeout = aiohttp.ClientTimeout(total=timeout)
134
205
  self._follow_redirects = follow_redirects
135
206
  self._max_connections = max_connections
136
207
  self._retry_config = retry_config or RetryConfig()
137
208
  self._interceptors: list[RequestInterceptor] = []
138
209
 
139
- # 创建HTTP客户端(使用连接池)
140
- limits = httpx.Limits(
141
- max_connections=max_connections,
142
- max_keepalive_connections=20,
143
- keepalive_expiry=5.0,
210
+ # 创建连接器(连接池)
211
+ self._connector = aiohttp.TCPConnector(
212
+ limit=max_connections,
213
+ limit_per_host=max_connections // 4,
214
+ keepalive_timeout=30,
215
+ enable_cleanup_closed=True,
144
216
  )
145
217
 
146
- self._client = httpx.AsyncClient(
147
- base_url=base_url,
148
- timeout=timeout,
149
- follow_redirects=follow_redirects,
150
- limits=limits,
151
- )
218
+ # aiohttp 会话(延迟创建)
219
+ self._session: aiohttp.ClientSession | None = None
152
220
 
153
221
  logger.debug(f"HTTP客户端初始化: base_url={base_url}, timeout={timeout}")
154
222
 
223
+ async def _ensure_session(self) -> aiohttp.ClientSession:
224
+ """确保会话已创建。"""
225
+ if self._session is None or self._session.closed:
226
+ self._session = aiohttp.ClientSession(
227
+ connector=self._connector,
228
+ timeout=self._timeout,
229
+ )
230
+ return self._session
231
+
155
232
  @classmethod
156
233
  def from_config(cls, config: HttpClientConfig) -> HttpClient:
157
234
  """从配置创建客户端。
@@ -181,9 +258,9 @@ class HttpClient:
181
258
 
182
259
  async def _apply_interceptors(
183
260
  self,
184
- request: httpx.Request,
185
- response: httpx.Response | None = None,
186
- ) -> tuple[httpx.Request, httpx.Response | None]:
261
+ request: HttpRequest,
262
+ response: HttpResponse | None = None,
263
+ ) -> tuple[HttpRequest, HttpResponse | None]:
187
264
  """应用拦截器。"""
188
265
  # 请求前拦截
189
266
  for interceptor in self._interceptors:
@@ -196,28 +273,6 @@ class HttpClient:
196
273
 
197
274
  return request, response
198
275
 
199
- async def _make_request(
200
- self,
201
- method: str,
202
- url: str,
203
- **kwargs: Any,
204
- ) -> httpx.Response:
205
- """执行HTTP请求(内部方法,使用tenacity重试)。"""
206
- response = await self._client.request(method, url, **kwargs)
207
-
208
- # 检查状态码是否需要重试
209
- if response.status_code in self._retry_config.retry_on_status:
210
- logger.warning(
211
- f"请求失败,状态码: {response.status_code}, 将重试"
212
- )
213
- raise httpx.HTTPStatusError(
214
- f"HTTP {response.status_code}",
215
- request=response.request,
216
- response=response,
217
- )
218
-
219
- return response
220
-
221
276
  def _get_retry_decorator(self):
222
277
  """动态构建重试装饰器。"""
223
278
  return retry(
@@ -227,7 +282,7 @@ class HttpClient:
227
282
  min=self._retry_config.retry_delay,
228
283
  max=self._retry_config.retry_delay * (self._retry_config.backoff_factor ** self._retry_config.max_retries),
229
284
  ),
230
- retry=retry_if_exception_type(*self._retry_config.retry_on_exceptions),
285
+ retry=retry_if_exception_type((HttpStatusError, aiohttp.ClientError)),
231
286
  reraise=True,
232
287
  )
233
288
 
@@ -240,9 +295,8 @@ class HttpClient:
240
295
  params: dict[str, Any] | None = None,
241
296
  json: Any = None,
242
297
  data: Any = None,
243
- files: Any = None,
244
298
  **kwargs: Any,
245
- ) -> httpx.Response:
299
+ ) -> HttpResponse:
246
300
  """发送HTTP请求。
247
301
 
248
302
  Args:
@@ -252,48 +306,79 @@ class HttpClient:
252
306
  params: 查询参数
253
307
  json: JSON数据
254
308
  data: 表单数据
255
- files: 文件
256
- **kwargs: 其他参数
309
+ **kwargs: 其他 aiohttp 参数
257
310
 
258
311
  Returns:
259
- httpx.Response: 响应对象
312
+ HttpResponse: 响应对象
260
313
 
261
314
  Raises:
262
- httpx.HTTPError: 请求失败
315
+ HttpError: 请求失败
263
316
  """
264
317
  # 构建完整URL
265
318
  full_url = f"{self._base_url}{url}" if self._base_url else url
266
319
 
267
320
  # 创建请求对象
268
- request = self._client.build_request(
321
+ request = HttpRequest(
269
322
  method=method,
270
323
  url=full_url,
271
- headers=headers,
324
+ headers=headers or {},
272
325
  params=params,
273
- json=json,
326
+ json_data=json,
274
327
  data=data,
275
- files=files,
276
- **kwargs,
277
328
  )
278
329
 
279
330
  # 应用拦截器(请求前)
280
331
  request, _ = await self._apply_interceptors(request)
281
332
 
333
+ session = await self._ensure_session()
334
+
335
+ async def _execute_request() -> HttpResponse:
336
+ start_time = time.perf_counter()
337
+ try:
338
+ async with session.request(
339
+ method=request.method,
340
+ url=request.url,
341
+ headers=request.headers or None,
342
+ params=request.params,
343
+ json=request.json_data,
344
+ data=request.data,
345
+ allow_redirects=self._follow_redirects,
346
+ **kwargs,
347
+ ) as resp:
348
+ elapsed = time.perf_counter() - start_time
349
+ content = await resp.read()
350
+ text = content.decode("utf-8", errors="replace")
351
+
352
+ response = HttpResponse(
353
+ status_code=resp.status,
354
+ url=str(resp.url),
355
+ headers=dict(resp.headers),
356
+ text=text,
357
+ content=content,
358
+ elapsed_seconds=elapsed,
359
+ )
360
+
361
+ # 检查是否需要重试
362
+ if resp.status in self._retry_config.retry_on_status:
363
+ logger.warning(f"请求失败,状态码: {resp.status}, 将重试")
364
+ raise HttpStatusError(
365
+ f"HTTP {resp.status}",
366
+ status_code=resp.status,
367
+ response=response,
368
+ )
369
+
370
+ return response
371
+
372
+ except aiohttp.ClientError as exc:
373
+ elapsed = time.perf_counter() - start_time
374
+ if isinstance(exc, aiohttp.ServerTimeoutError):
375
+ raise HttpTimeoutError(f"请求超时: {request.url}") from exc
376
+ raise HttpNetworkError(f"网络错误: {exc}") from exc
377
+
282
378
  try:
283
379
  # 使用tenacity重试装饰器
284
380
  retry_decorator = self._get_retry_decorator()
285
-
286
- @retry_decorator
287
- async def _execute_request():
288
- return await self._make_request(
289
- method=request.method,
290
- url=str(request.url),
291
- headers=request.headers,
292
- content=request.content,
293
- **kwargs,
294
- )
295
-
296
- response = await _execute_request()
381
+ response = await retry_decorator(_execute_request)()
297
382
 
298
383
  # 应用拦截器(响应后)
299
384
  _, response = await self._apply_interceptors(request, response)
@@ -303,44 +388,49 @@ class HttpClient:
303
388
 
304
389
  return response
305
390
 
306
- except httpx.HTTPError as exc:
391
+ except HttpError:
392
+ raise
393
+ except Exception as exc:
307
394
  logger.error(
308
395
  f"HTTP请求失败: {method} {full_url} | "
309
396
  f"错误: {type(exc).__name__}: {exc}"
310
397
  )
311
- raise
398
+ raise HttpNetworkError(f"请求失败: {exc}") from exc
312
399
 
313
- async def get(self, url: str, **kwargs: Any) -> httpx.Response:
400
+ async def get(self, url: str, **kwargs: Any) -> HttpResponse:
314
401
  """GET请求。"""
315
402
  return await self.request("GET", url, **kwargs)
316
403
 
317
- async def post(self, url: str, **kwargs: Any) -> httpx.Response:
404
+ async def post(self, url: str, **kwargs: Any) -> HttpResponse:
318
405
  """POST请求。"""
319
406
  return await self.request("POST", url, **kwargs)
320
407
 
321
- async def put(self, url: str, **kwargs: Any) -> httpx.Response:
408
+ async def put(self, url: str, **kwargs: Any) -> HttpResponse:
322
409
  """PUT请求。"""
323
410
  return await self.request("PUT", url, **kwargs)
324
411
 
325
- async def patch(self, url: str, **kwargs: Any) -> httpx.Response:
412
+ async def patch(self, url: str, **kwargs: Any) -> HttpResponse:
326
413
  """PATCH请求。"""
327
414
  return await self.request("PATCH", url, **kwargs)
328
415
 
329
- async def delete(self, url: str, **kwargs: Any) -> httpx.Response:
416
+ async def delete(self, url: str, **kwargs: Any) -> HttpResponse:
330
417
  """DELETE请求。"""
331
418
  return await self.request("DELETE", url, **kwargs)
332
419
 
333
- async def head(self, url: str, **kwargs: Any) -> httpx.Response:
420
+ async def head(self, url: str, **kwargs: Any) -> HttpResponse:
334
421
  """HEAD请求。"""
335
422
  return await self.request("HEAD", url, **kwargs)
336
423
 
337
- async def options(self, url: str, **kwargs: Any) -> httpx.Response:
424
+ async def options(self, url: str, **kwargs: Any) -> HttpResponse:
338
425
  """OPTIONS请求。"""
339
426
  return await self.request("OPTIONS", url, **kwargs)
340
427
 
341
428
  async def close(self) -> None:
342
429
  """关闭客户端。"""
343
- await self._client.aclose()
430
+ if self._session and not self._session.closed:
431
+ await self._session.close()
432
+ if self._connector and not self._connector.closed:
433
+ await self._connector.close()
344
434
  logger.debug("HTTP客户端已关闭")
345
435
 
346
436
  async def __aenter__(self) -> HttpClient:
@@ -353,15 +443,20 @@ class HttpClient:
353
443
 
354
444
  def __repr__(self) -> str:
355
445
  """字符串表示。"""
356
- return f"<HttpClient base_url={self._base_url} timeout={self._timeout}>"
446
+ return f"<HttpClient base_url={self._base_url} timeout={self._timeout.total}>"
357
447
 
358
448
 
359
449
  __all__ = [
360
450
  "HttpClient",
361
451
  "HttpClientConfig",
452
+ "HttpError",
453
+ "HttpNetworkError",
454
+ "HttpRequest",
455
+ "HttpResponse",
456
+ "HttpStatusError",
457
+ "HttpTimeoutError",
362
458
  "LoggingInterceptor",
363
459
  "RequestInterceptor",
364
460
  "RetryConfig",
365
461
  ]
366
462
 
367
-
@@ -1,8 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aury-boot
3
- Version: 0.0.39
3
+ Version: 0.0.40
4
4
  Summary: Aury Boot - 基于 FastAPI 生态的企业级 API 开发框架
5
5
  Requires-Python: >=3.13
6
+ Requires-Dist: aiohttp>=3.11.0
6
7
  Requires-Dist: alembic>=1.17.2
7
8
  Requires-Dist: aury-sdk-storage[aws]>=0.0.6
8
9
  Requires-Dist: babel>=2.17.0
@@ -10,7 +11,6 @@ Requires-Dist: broadcaster[redis]>=0.3.1
10
11
  Requires-Dist: faker>=38.2.0
11
12
  Requires-Dist: fastapi>=0.122.0
12
13
  Requires-Dist: greenlet>=3.2.4
13
- Requires-Dist: httpx>=0.28.1
14
14
  Requires-Dist: loguru>=0.7.3
15
15
  Requires-Dist: pydantic-settings>=2.12.0
16
16
  Requires-Dist: pydantic>=2.12.5
@@ -30,10 +30,13 @@ Requires-Dist: asyncpg>=0.31.0; extra == 'all'
30
30
  Requires-Dist: aury-sdk-storage[aws]>=0.0.1; extra == 'all'
31
31
  Requires-Dist: dramatiq>=1.18.0; extra == 'all'
32
32
  Requires-Dist: pika>=1.3.2; extra == 'all'
33
+ Requires-Dist: psutil>=7.0.0; extra == 'all'
34
+ Requires-Dist: pyroscope-io>=0.8.7; extra == 'all'
33
35
  Requires-Dist: redis>=7.1.0; extra == 'all'
34
36
  Provides-Extra: broadcaster
35
37
  Requires-Dist: broadcaster[redis]>=0.3.1; extra == 'broadcaster'
36
38
  Provides-Extra: dev
39
+ Requires-Dist: httpx>=0.28.1; extra == 'dev'
37
40
  Requires-Dist: mypy>=1.19.0; extra == 'dev'
38
41
  Requires-Dist: pytest-asyncio>=1.3.0; extra == 'dev'
39
42
  Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
@@ -47,14 +50,17 @@ Provides-Extra: mysql
47
50
  Requires-Dist: aiomysql>=0.3.2; extra == 'mysql'
48
51
  Provides-Extra: otel
49
52
  Requires-Dist: opentelemetry-api>=1.25.0; extra == 'otel'
53
+ Requires-Dist: opentelemetry-instrumentation-aiohttp-client>=0.46b0; extra == 'otel'
50
54
  Requires-Dist: opentelemetry-instrumentation-fastapi>=0.46b0; extra == 'otel'
51
- Requires-Dist: opentelemetry-instrumentation-httpx>=0.46b0; extra == 'otel'
52
55
  Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.46b0; extra == 'otel'
53
56
  Requires-Dist: opentelemetry-sdk>=1.25.0; extra == 'otel'
54
57
  Provides-Extra: otel-exporter
55
58
  Requires-Dist: opentelemetry-exporter-otlp>=1.25.0; extra == 'otel-exporter'
56
59
  Provides-Extra: postgres
57
60
  Requires-Dist: asyncpg>=0.31.0; extra == 'postgres'
61
+ Provides-Extra: profiling
62
+ Requires-Dist: psutil>=7.0.0; extra == 'profiling'
63
+ Requires-Dist: pyroscope-io>=0.8.7; extra == 'profiling'
58
64
  Provides-Extra: rabbitmq
59
65
  Requires-Dist: amqp>=5.3.1; extra == 'rabbitmq'
60
66
  Provides-Extra: recommended
@@ -64,8 +70,8 @@ Requires-Dist: asyncpg>=0.31.0; extra == 'recommended'
64
70
  Requires-Dist: aury-sdk-storage[aws]>=0.0.1; extra == 'recommended'
65
71
  Requires-Dist: dramatiq>=1.18.0; extra == 'recommended'
66
72
  Requires-Dist: opentelemetry-api>=1.25.0; extra == 'recommended'
73
+ Requires-Dist: opentelemetry-instrumentation-aiohttp-client>=0.46b0; extra == 'recommended'
67
74
  Requires-Dist: opentelemetry-instrumentation-fastapi>=0.46b0; extra == 'recommended'
68
- Requires-Dist: opentelemetry-instrumentation-httpx>=0.46b0; extra == 'recommended'
69
75
  Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.46b0; extra == 'recommended'
70
76
  Requires-Dist: opentelemetry-sdk>=1.25.0; extra == 'recommended'
71
77
  Requires-Dist: redis>=7.1.0; extra == 'recommended'
@@ -1,20 +1,20 @@
1
1
  aury/boot/__init__.py,sha256=pCno-EInnpIBa1OtxNYF-JWf9j95Cd2h6vmu0xqa_-4,1791
2
- aury/boot/_version.py,sha256=4ZEdlNp6MHArYK_GfVRp7IC9mBDzzgBih3DH2hlHeCo,706
2
+ aury/boot/_version.py,sha256=iVCKwk3ALZWN3TArFywN2NsKO1DSIjrjwe22g3qygd0,706
3
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
7
7
  aury/boot/application/adapter/decorators.py,sha256=yyGu_16bWWUiO36gxCeQWgG0DN19p5PqjHQan_Fvi0A,8959
8
8
  aury/boot/application/adapter/exceptions.py,sha256=Kzm-ytRxdUnSMIcWCSOHPxo4Jh_A6YbyxlOVIUs-5F4,6183
9
- aury/boot/application/adapter/http.py,sha256=4TADsSzdSRU63307dmmo-2U_JpVP12mwTFy66B5Ps-w,10759
9
+ aury/boot/application/adapter/http.py,sha256=aKwjlelW9BeH1FFF_MA0o8R5bnKdWYoG6VKjJMB81JA,11042
10
10
  aury/boot/application/app/__init__.py,sha256=I8FfCKDuDQsGzAK6BevyfdtAwieMUVYu6qgVQzBazpE,830
11
- aury/boot/application/app/base.py,sha256=kyuNm3wOr8cnrPlKJOLJUBQY2-91q5LZABtoUGkmg7g,21634
12
- aury/boot/application/app/components.py,sha256=Ub7NlfxSPXSDcxUajQ5ed42kNmsBSol-UttcBfnx64Y,33473
11
+ aury/boot/application/app/base.py,sha256=oLktBx008BzLmRRwUO4AvLVD-gEpJOx-tS-bip7lFfU,21674
12
+ aury/boot/application/app/components.py,sha256=rMNc5XU6aIH8fjg_gLFb1C1W9RYKxcjQX-WD_D0M4Rg,36889
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=JZuLVKH13cuBdlHdtrt7ZZ4d7KD8as5DWBv0d9enHDk,38026
17
+ aury/boot/application/config/settings.py,sha256=Ia-RXXEdgxiCZCNksUIzEK1qG9qQvF81SnSW_YqaN5A,40453
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
@@ -47,8 +47,8 @@ aury/boot/commands/config.py,sha256=gPkG_jSWrXidjpyVdzABH7uRhoCgX5yrOcdKabtX5wY,
47
47
  aury/boot/commands/docker.py,sha256=7mKorZCPZgxH1XFslzo6W-uzpe61hGXz86JKOhOeBlo,9006
48
48
  aury/boot/commands/docs.py,sha256=Hz1W-2TW8DzaPxARqEF4UncPhGMI9h97jJ962dlox3U,14327
49
49
  aury/boot/commands/generate.py,sha256=WZieSXuofxJOC7NBiVGpBigB9NZ4GMcF2F1ReTNun1I,44420
50
- aury/boot/commands/init.py,sha256=6reBpZ5jS4O9QTfXHKt4MCXPn3WcubjUfOtB5tKdy0s,32349
51
- aury/boot/commands/pkg.py,sha256=bw0QPptKscNgQ4I1SfSehTio9Q5KrvxgvkYx4tbZ7Vs,14495
50
+ aury/boot/commands/init.py,sha256=MISHy3dKTtgZKoQ-4xZZ75WUhqgOK5uLVsb-juNvq_s,33000
51
+ aury/boot/commands/pkg.py,sha256=M2dHT6o9B1aCDnjfDjuko2jk2Z0BrR_U8yYtfpQl6MU,15704
52
52
  aury/boot/commands/scheduler.py,sha256=XO3Gq7PqNxXNz5Gw0xNUHa_bEnAKZ9AkzLc062QJ3j8,3669
53
53
  aury/boot/commands/worker.py,sha256=OEvfDiiM_pV3Mj73HKhSm1RNqFPuS125iNM0qNCTHFY,4316
54
54
  aury/boot/commands/migrate/__init__.py,sha256=W9OhkX8ILdolySofgdP2oYoJGG9loQd5FeSwkniU3qM,455
@@ -69,7 +69,7 @@ aury/boot/commands/templates/project/config.py.tpl,sha256=H_B05FypBJxTjb7qIL91zC
69
69
  aury/boot/commands/templates/project/conftest.py.tpl,sha256=chbETK81Hy26cWz6YZ2cFgy7HbnABzYCqeyMzgpa3eI,726
70
70
  aury/boot/commands/templates/project/gitignore.tpl,sha256=OI0nt9u2E9EC-jAMoh3gpqamsWo18uDgyPybgee_snQ,3053
71
71
  aury/boot/commands/templates/project/main.py.tpl,sha256=6uiXv8KuGl24qZfzgFI2twB6WYCWHXCGMfwirezF8L4,1217
72
- aury/boot/commands/templates/project/aury_docs/00-overview.md.tpl,sha256=eOjtqMeKqZ8OgijrOwcpfpHhrhUvt_CiHPUtRG0dilA,2251
72
+ aury/boot/commands/templates/project/aury_docs/00-overview.md.tpl,sha256=AcnT1lSD14fkP6ZeDYEjtx75yCgohW_2iSaTkJz2XHU,2362
73
73
  aury/boot/commands/templates/project/aury_docs/01-model.md.tpl,sha256=1mQ3hGDxqEZjev4CD5-3dzYRFVonPNcAaStI1UBEUyM,6811
74
74
  aury/boot/commands/templates/project/aury_docs/02-repository.md.tpl,sha256=Pn3pT9RoBponTcc4tvepFkVcE8EKxu2F9JaHPJ_mDk8,8345
75
75
  aury/boot/commands/templates/project/aury_docs/03-service.md.tpl,sha256=SgfPAgLVi_RbMjSAe-m49jQOIr6vfUT8VF2V1E-qa3w,15098
@@ -87,6 +87,7 @@ aury/boot/commands/templates/project/aury_docs/14-mq.md.tpl,sha256=irrKal6y8pPAj
87
87
  aury/boot/commands/templates/project/aury_docs/15-events.md.tpl,sha256=a4wQRgVPuYUGTGmw_lX1HJH_yFTbD30mBz7Arc4zgfs,3361
88
88
  aury/boot/commands/templates/project/aury_docs/16-adapter.md.tpl,sha256=pkmJkZw2Ca6_uYk2jZvAb8DozjBa2tWq_t3gtq1lFSk,11456
89
89
  aury/boot/commands/templates/project/aury_docs/17-alerting.md.tpl,sha256=2MosApSAuGerBw7SOO-ihk4NTp2qEkgOUyu6pS2m0UY,5709
90
+ aury/boot/commands/templates/project/aury_docs/18-monitoring-profiling.md.tpl,sha256=KuLStB1LWSLfH2o2BPiwHGkkOsWv7ZyF-3piV8hHYiY,5338
90
91
  aury/boot/commands/templates/project/aury_docs/99-cli.md.tpl,sha256=9JSdiAbu3SGmmF_iCslw5LBPlks2DYf4WYw05pA_2_I,5673
91
92
  aury/boot/commands/templates/project/env_templates/_header.tpl,sha256=Pt0X_I25o1th3CLR228L2-nlcC-lIkN8cPailohBEkU,513
92
93
  aury/boot/commands/templates/project/env_templates/admin.tpl,sha256=wWt3iybOpBHtuw6CkoUJ1bzEL0aNgOzKDEkMKhI2oag,2032
@@ -94,7 +95,7 @@ aury/boot/commands/templates/project/env_templates/cache.tpl,sha256=_sK-p_FECj4m
94
95
  aury/boot/commands/templates/project/env_templates/database.tpl,sha256=2lWzTKt4X0SpeBBCkrDV90Di4EfoAuqYzhVsh74vTUI,907
95
96
  aury/boot/commands/templates/project/env_templates/log.tpl,sha256=x5rkrEFJISH0gaCcr-wTCbDYtyFnlLNJpY789fqjZgc,754
96
97
  aury/boot/commands/templates/project/env_templates/messaging.tpl,sha256=AgfsXTRnvDySFERoCVop89jsC_h8hzj1sPeq5MczSXM,2462
97
- aury/boot/commands/templates/project/env_templates/monitoring.tpl,sha256=Zq0xQzDrCRtbeLCQB3pkEE2p8FFED6IjQo4TqMyd_P8,2584
98
+ aury/boot/commands/templates/project/env_templates/monitoring.tpl,sha256=jtzmV3mdD9NOqKyxtq35UGM7MbWqxLvu2Y5OfOy2Hlo,3153
98
99
  aury/boot/commands/templates/project/env_templates/rpc.tpl,sha256=FhweCFakawGLSs01a_BkmZo11UhWax2-VCBudHj68WA,1163
99
100
  aury/boot/commands/templates/project/env_templates/scheduler.tpl,sha256=c8Grcs1rgBB58RHlxqmDMPHQl8BnbcqNW473ctmsojU,752
100
101
  aury/boot/commands/templates/project/env_templates/service.tpl,sha256=b-a2GyRyoaunbDj_2kaSw3OFxcugscmPvUBG7w0XO8c,710
@@ -112,7 +113,7 @@ aury/boot/common/logging/__init__.py,sha256=SNuqbEKaraqYwB8qM6mQUl55lXJNPb1tLujP
112
113
  aury/boot/common/logging/context.py,sha256=ndml3rUokEIt5-845E5aW8jI8b4N93ZtukyqsjqzuNE,2566
113
114
  aury/boot/common/logging/decorators.py,sha256=UaGMhRJdARNJ2VgCuRwaNX0DD5wIc1gAl6NDj7u8K2c,3354
114
115
  aury/boot/common/logging/format.py,sha256=ZEqLagTdyGadywTamybcEh1fAZng3Wfx7DC952TFU30,9782
115
- aury/boot/common/logging/setup.py,sha256=gPzappMVB372rlEIZvWR8QMOhyv0S2r70WB7LaonRNY,9619
116
+ aury/boot/common/logging/setup.py,sha256=JNOFu1t-Xjfcb66BqFiyyn7oMKM90P9cDv8rcHJMzqI,9935
116
117
  aury/boot/contrib/__init__.py,sha256=fyk_St9VufIx64hsobv9EsOYzb_T5FbJHxjqtPds4g8,198
117
118
  aury/boot/contrib/admin_console/__init__.py,sha256=HEesLFrtYtBFWTDrh5H3mR-4V4LRg5N4a2a1C4-Whgs,445
118
119
  aury/boot/contrib/admin_console/auth.py,sha256=_goyjZ8Clssvmy8g84svenGfBqCe9OC5pIvCjIzt42g,4706
@@ -158,7 +159,7 @@ aury/boot/infrastructure/clients/redis/manager.py,sha256=Dmfu6OWGe_PrBr9wbOhl3su
158
159
  aury/boot/infrastructure/database/__init__.py,sha256=MsHNyrJ2CZJT-lbVZzOAJ0nFfFEmHrJqC0zw-cFS768,888
159
160
  aury/boot/infrastructure/database/config.py,sha256=5LYy4DuLL0XNjVnX2HUcrMh3c71eeZa-vWGM8QCkL0U,1408
160
161
  aury/boot/infrastructure/database/exceptions.py,sha256=hUjsU23c0eMwogSDrKq_bQ6zvnY7PQSGaitbCEhhDZQ,766
161
- aury/boot/infrastructure/database/manager.py,sha256=lRSKL9jDkSdaA99DjD1k4EoQuQsn2vbh9XQQBOt9dM0,10317
162
+ aury/boot/infrastructure/database/manager.py,sha256=KD2mMMp-pcvW8WqTMdJ914RvFd1dH3phAB4elQ2fHGM,10369
162
163
  aury/boot/infrastructure/database/query_tools/__init__.py,sha256=pOFuyDDNpkY5cSMJ-O6UA0-5Lq96-Zvt4FaYMhiwaMg,5488
163
164
  aury/boot/infrastructure/database/strategies/__init__.py,sha256=foj_2xEsgLZxshpK65YAhdJ2UZyh1tKvGRq6sre8pQY,5909
164
165
  aury/boot/infrastructure/di/__init__.py,sha256=qFYlk265d6_rS8OiX37_wOc7mBFw8hk3yipDYNkyjQg,231
@@ -170,7 +171,7 @@ aury/boot/infrastructure/events/middleware.py,sha256=Ck3qNMTtLuFFKsJuEUeOMG9nu3q
170
171
  aury/boot/infrastructure/events/backends/__init__.py,sha256=1mj0rDauHdoRm4kXOg87l2f9jnMbj_jKZdVnIZMj9XM,185
171
172
  aury/boot/infrastructure/events/backends/broadcaster.py,sha256=FnxO62LUXWLs1ZEiaYmNiMaL3ccXNtuc3DFzLe02eK0,6700
172
173
  aury/boot/infrastructure/events/backends/rabbitmq.py,sha256=XCuI9mc3GR-t0zht4yZ3e2nnyFl8UuTDir_0nsDbfxM,6495
173
- aury/boot/infrastructure/monitoring/__init__.py,sha256=KGtJU0slbRvFzzUv60LQHB12sX7eNNvGDu8Lyk9Owy8,22415
174
+ aury/boot/infrastructure/monitoring/__init__.py,sha256=F9bVYegERpzU3UoqCpJWQDyDWK_NN8_q_6xThyaYSdE,22752
174
175
  aury/boot/infrastructure/monitoring/alerting/__init__.py,sha256=UvUsMhSZeGJOjZy05FnkZQmWytBlz3wiRd0y8EfZgpY,1413
175
176
  aury/boot/infrastructure/monitoring/alerting/aggregator.py,sha256=fiI-lBSqWxXv1eVPfaDNjcigX-81w41fcmhD_vN_XSs,5805
176
177
  aury/boot/infrastructure/monitoring/alerting/events.py,sha256=zJvTevQ-9JflIDyYVo1BRzOVyAGhdgEfRlMsD0NcBgM,4056
@@ -178,9 +179,10 @@ aury/boot/infrastructure/monitoring/alerting/manager.py,sha256=vdWox9Pnjl_0IIE6w
178
179
  aury/boot/infrastructure/monitoring/alerting/rules.py,sha256=FdyGOolQJF31fN_9mqRGi9i_x2JqtoHEOkNOcPyO07o,6124
179
180
  aury/boot/infrastructure/monitoring/alerting/notifiers/__init__.py,sha256=dsfxThPHO_Ofb3Wo_dYlL8HvP_N63pb_S_UXm_qSxF8,321
180
181
  aury/boot/infrastructure/monitoring/alerting/notifiers/base.py,sha256=_RXZMzWX-YeTG0Up1U8CwK8ADfX34dd0Sh56ugfqOWM,1462
181
- aury/boot/infrastructure/monitoring/alerting/notifiers/feishu.py,sha256=JAMJiCNRYoDeJrYn29ew_ZVXDGq8OLgiFApRWd4iPY0,7134
182
- aury/boot/infrastructure/monitoring/alerting/notifiers/webhook.py,sha256=EiGtLCztHoyjRTR3cvhguRMXbMkScfwY_mXRy9AD5Vw,3514
182
+ aury/boot/infrastructure/monitoring/alerting/notifiers/feishu.py,sha256=7IdJruRsapvr4aWWnil8ijYu81wIJ8ISH2IE3Dk0wO4,8310
183
+ aury/boot/infrastructure/monitoring/alerting/notifiers/webhook.py,sha256=2PlS95sIS1HkZaedZW-tAMYjLquk1YWpPFjMMYCBM4M,3644
183
184
  aury/boot/infrastructure/monitoring/health/__init__.py,sha256=nqwFFXl6J9yTfQa1JLjQDs4hS4qSVEeA4w07JWdt4jM,7305
185
+ aury/boot/infrastructure/monitoring/profiling/__init__.py,sha256=SmeGZzb-vHIwmt4l_oDzZS35Y-Qfei8kU7e2K7-AufY,20169
184
186
  aury/boot/infrastructure/monitoring/tracing/__init__.py,sha256=YizkpnhY-bcUUcd8YaDzUsluMflhNOH1dAKdVtkW05U,1287
185
187
  aury/boot/infrastructure/monitoring/tracing/context.py,sha256=s_k2MzNl4LDDpei9xUP6TFW5BwZneoQg44RPaw95jac,978
186
188
  aury/boot/infrastructure/monitoring/tracing/logging.py,sha256=gzuKa1ZiyY4z06fHNTbjgZasS6mLftSEaZQQ-Z6J_RE,2041
@@ -196,7 +198,7 @@ aury/boot/infrastructure/mq/backends/redis.py,sha256=B89U7mqIceUsCXE4G3u1u6aFM9h
196
198
  aury/boot/infrastructure/mq/backends/redis_stream.py,sha256=p2WTj10-zbxQ_2NPU97w-n4DZ8KSHhLjqcnplLPCw4U,14761
197
199
  aury/boot/infrastructure/scheduler/__init__.py,sha256=eTRJ5dSPcKvyFvLVtraoQteXTTDDGwIrmw06J2hoNdA,323
198
200
  aury/boot/infrastructure/scheduler/exceptions.py,sha256=ROltrhSctVWA-6ulnjuYeHAk3ZF-sykDoesuierYzew,634
199
- aury/boot/infrastructure/scheduler/manager.py,sha256=OHQOHQlcoN8yFnky4kfuhsEIk39qX6nLZ7xJ51tfg68,23130
201
+ aury/boot/infrastructure/scheduler/manager.py,sha256=wUxMRGXpoAwjHnB4u7BKnzJbiPZE5sovuLPrgLoQYb4,23753
200
202
  aury/boot/infrastructure/storage/__init__.py,sha256=bA-n3v2S1FX6XsQbLqt0hkgx512MjUn_b8kJo53G6gA,1238
201
203
  aury/boot/infrastructure/storage/base.py,sha256=X9aswSMWtKZ6TdG5Rrh6qJpqIVLt1QcFkQAKdyUWPi0,5039
202
204
  aury/boot/infrastructure/storage/exceptions.py,sha256=Av1r94bRkeeeDo6vgAD9e_9YA9Ge6D7F2U1qzUs-8FE,622
@@ -211,8 +213,8 @@ aury/boot/testing/base.py,sha256=BQOA6V4RIecVJM9t7kto9YxL0Ij_jEsFBdpKceWBe3U,372
211
213
  aury/boot/testing/client.py,sha256=KOg1EemuIVsBG68G5y0DjSxZGcIQVdWQ4ASaHE3o1R0,4484
212
214
  aury/boot/testing/factory.py,sha256=8GvwX9qIDu0L65gzJMlrWB0xbmJ-7zPHuwk3eECULcg,5185
213
215
  aury/boot/toolkit/__init__.py,sha256=AcyVb9fDf3CaEmJPNkWC4iGv32qCPyk4BuFKSuNiJRQ,334
214
- aury/boot/toolkit/http/__init__.py,sha256=zIPmpIZ9Qbqe25VmEr7jixoY2fkRbLm7NkCB9vKpg6I,11039
215
- aury_boot-0.0.39.dist-info/METADATA,sha256=qX6IZza7loT9gQzeJlbhPz1QKshBy3fZH__Fic8U1s0,8694
216
- aury_boot-0.0.39.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
217
- aury_boot-0.0.39.dist-info/entry_points.txt,sha256=f9KXEkDIGc0BGkgBvsNx_HMz9VhDjNxu26q00jUpDwQ,49
218
- aury_boot-0.0.39.dist-info/RECORD,,
216
+ aury/boot/toolkit/http/__init__.py,sha256=5bv4Ntz1sbNFhP9zPLBDhB536ZX1CKIAOp-kQSKMRQ0,14161
217
+ aury_boot-0.0.40.dist-info/METADATA,sha256=8deP0tWBoSZqiF32QRvpvTkeNS0J3YEReU9HvER9TIw,8989
218
+ aury_boot-0.0.40.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
219
+ aury_boot-0.0.40.dist-info/entry_points.txt,sha256=f9KXEkDIGc0BGkgBvsNx_HMz9VhDjNxu26q00jUpDwQ,49
220
+ aury_boot-0.0.40.dist-info/RECORD,,