aury-boot 0.0.36__py3-none-any.whl → 0.0.38__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.
@@ -0,0 +1,306 @@
1
+ """内存和 Memcached 缓存后端实现。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import fnmatch
7
+ import json
8
+ import time
9
+ from datetime import timedelta
10
+ from typing import Any
11
+
12
+ from aury.boot.common.logging import logger
13
+
14
+ from .base import ICache
15
+
16
+
17
+ class MemoryCache(ICache):
18
+ """内存缓存实现。"""
19
+
20
+ def __init__(self, max_size: int = 1000):
21
+ """初始化内存缓存。
22
+
23
+ Args:
24
+ max_size: 最大缓存项数
25
+ """
26
+ self._max_size = max_size
27
+ self._cache: dict[str, tuple[Any, float | None]] = {}
28
+ self._lock = asyncio.Lock()
29
+
30
+ async def get(self, key: str, default: Any = None) -> Any:
31
+ """获取缓存。"""
32
+ async with self._lock:
33
+ if key not in self._cache:
34
+ return default
35
+
36
+ value, expire_at = self._cache[key]
37
+
38
+ # 检查过期
39
+ if expire_at is not None and asyncio.get_event_loop().time() > expire_at:
40
+ del self._cache[key]
41
+ return default
42
+
43
+ return value
44
+
45
+ async def set(
46
+ self,
47
+ key: str,
48
+ value: Any,
49
+ expire: int | timedelta | None = None,
50
+ ) -> bool:
51
+ """设置缓存。"""
52
+ async with self._lock:
53
+ # 转换过期时间
54
+ expire_at = None
55
+ if expire:
56
+ if isinstance(expire, timedelta):
57
+ expire_seconds = expire.total_seconds()
58
+ else:
59
+ expire_seconds = expire
60
+ expire_at = asyncio.get_event_loop().time() + expire_seconds
61
+
62
+ # 如果超出容量,删除最旧的
63
+ if len(self._cache) >= self._max_size and key not in self._cache:
64
+ # 简单策略:删除第一个
65
+ first_key = next(iter(self._cache))
66
+ del self._cache[first_key]
67
+
68
+ self._cache[key] = (value, expire_at)
69
+ return True
70
+
71
+ async def delete(self, *keys: str) -> int:
72
+ """删除缓存。"""
73
+ async with self._lock:
74
+ count = 0
75
+ for key in keys:
76
+ if key in self._cache:
77
+ del self._cache[key]
78
+ count += 1
79
+ return count
80
+
81
+ async def exists(self, *keys: str) -> int:
82
+ """检查缓存是否存在。"""
83
+ async with self._lock:
84
+ count = 0
85
+ for key in keys:
86
+ if key in self._cache:
87
+ _value, expire_at = self._cache[key]
88
+ # 检查是否过期
89
+ if expire_at is None or asyncio.get_event_loop().time() <= expire_at:
90
+ count += 1
91
+ return count
92
+
93
+ async def clear(self) -> None:
94
+ """清空所有缓存。"""
95
+ async with self._lock:
96
+ self._cache.clear()
97
+ logger.info("内存缓存已清空")
98
+
99
+ async def delete_pattern(self, pattern: str) -> int:
100
+ """按模式删除缓存。
101
+
102
+ Args:
103
+ pattern: 通配符模式,支持 * 和 ?
104
+
105
+ Returns:
106
+ int: 删除的键数量
107
+ """
108
+ async with self._lock:
109
+ keys_to_delete = [
110
+ key for key in self._cache
111
+ if fnmatch.fnmatch(key, pattern)
112
+ ]
113
+ for key in keys_to_delete:
114
+ del self._cache[key]
115
+ logger.debug(f"按模式删除缓存: {pattern}, 删除 {len(keys_to_delete)} 个键")
116
+ return len(keys_to_delete)
117
+
118
+ async def close(self) -> None:
119
+ """关闭连接(内存缓存无需关闭)。"""
120
+ await self.clear()
121
+
122
+ async def size(self) -> int:
123
+ """获取缓存大小。"""
124
+ return len(self._cache)
125
+
126
+ # ==================== 内存锁 ====================
127
+
128
+ async def acquire_lock(
129
+ self,
130
+ key: str,
131
+ token: str,
132
+ timeout: int,
133
+ blocking: bool,
134
+ blocking_timeout: float | None,
135
+ ) -> bool:
136
+ """获取内存锁(单进程)。"""
137
+ start_time = time.monotonic()
138
+
139
+ while True:
140
+ async with self._lock:
141
+ # 检查锁是否存在
142
+ if key not in self._cache:
143
+ # 设置锁
144
+ expire_at = asyncio.get_event_loop().time() + timeout
145
+ self._cache[key] = (token, expire_at)
146
+ return True
147
+
148
+ # 检查锁是否过期
149
+ existing_token, expire_at = self._cache[key]
150
+ if expire_at is not None and asyncio.get_event_loop().time() > expire_at:
151
+ # 锁已过期,重新获取
152
+ new_expire_at = asyncio.get_event_loop().time() + timeout
153
+ self._cache[key] = (token, new_expire_at)
154
+ return True
155
+
156
+ if not blocking:
157
+ return False
158
+
159
+ # 检查是否超时
160
+ if blocking_timeout is not None:
161
+ elapsed = time.monotonic() - start_time
162
+ if elapsed >= blocking_timeout:
163
+ return False
164
+
165
+ # 短暂等待后重试
166
+ await asyncio.sleep(0.05)
167
+
168
+ async def release_lock(self, key: str, token: str) -> bool:
169
+ """释放内存锁。"""
170
+ async with self._lock:
171
+ if key not in self._cache:
172
+ return False
173
+
174
+ existing_token, _ = self._cache[key]
175
+ if existing_token == token:
176
+ del self._cache[key]
177
+ return True
178
+ return False
179
+
180
+
181
+ class MemcachedCache(ICache):
182
+ """Memcached缓存实现(可选)。"""
183
+
184
+ def __init__(self, servers: list[str]):
185
+ """初始化Memcached缓存。
186
+
187
+ Args:
188
+ servers: Memcached服务器列表,如 ["*********:11211"]
189
+ """
190
+ self._servers = servers
191
+ self._client = None
192
+
193
+ async def initialize(self) -> None:
194
+ """初始化连接。"""
195
+ try:
196
+ # 需要安装 python-memcached 或 aiomcache
197
+ try:
198
+ import aiomcache
199
+ self._client = aiomcache.Client(
200
+ self._servers[0].split(":")[0],
201
+ int(self._servers[0].split(":")[1]) if ":" in self._servers[0] else 11211,
202
+ )
203
+ logger.info("Memcached缓存初始化成功")
204
+ except ImportError:
205
+ logger.error("请安装 aiomcache: pip install aiomcache")
206
+ raise
207
+ except Exception as exc:
208
+ logger.error(f"Memcached连接失败: {exc}")
209
+ raise
210
+
211
+ async def get(self, key: str, default: Any = None) -> Any:
212
+ """获取缓存。"""
213
+ if not self._client:
214
+ return default
215
+
216
+ try:
217
+ data = await self._client.get(key.encode())
218
+ if data is None:
219
+ return default
220
+ return json.loads(data.decode())
221
+ except Exception as exc:
222
+ logger.error(f"Memcached获取失败: {key}, {exc}")
223
+ return default
224
+
225
+ async def set(
226
+ self,
227
+ key: str,
228
+ value: Any,
229
+ expire: int | timedelta | None = None,
230
+ ) -> bool:
231
+ """设置缓存。"""
232
+ if not self._client:
233
+ return False
234
+
235
+ try:
236
+ if isinstance(expire, timedelta):
237
+ expire = int(expire.total_seconds())
238
+
239
+ data = json.dumps(value).encode()
240
+ return await self._client.set(key.encode(), data, exptime=expire or 0)
241
+ except Exception as exc:
242
+ logger.error(f"Memcached设置失败: {key}, {exc}")
243
+ return False
244
+
245
+ async def delete(self, *keys: str) -> int:
246
+ """删除缓存。"""
247
+ if not self._client or not keys:
248
+ return 0
249
+
250
+ count = 0
251
+ for key in keys:
252
+ try:
253
+ if await self._client.delete(key.encode()):
254
+ count += 1
255
+ except Exception as exc:
256
+ logger.error(f"Memcached删除失败: {key}, {exc}")
257
+ return count
258
+
259
+ async def exists(self, *keys: str) -> int:
260
+ """检查缓存是否存在。"""
261
+ if not self._client or not keys:
262
+ return 0
263
+
264
+ count = 0
265
+ for key in keys:
266
+ try:
267
+ if await self._client.get(key.encode()) is not None:
268
+ count += 1
269
+ except Exception:
270
+ pass
271
+ return count
272
+
273
+ async def clear(self) -> None:
274
+ """清空所有缓存(Memcached不支持)。"""
275
+ logger.warning("Memcached不支持清空所有缓存")
276
+
277
+ async def delete_pattern(self, pattern: str) -> int:
278
+ """按模式删除缓存(Memcached 不支持)。"""
279
+ logger.warning("Memcached 不支持模式删除,请使用 Redis 或 Memory 后端")
280
+ return 0
281
+
282
+ async def close(self) -> None:
283
+ """关闭连接。"""
284
+ if self._client:
285
+ self._client.close()
286
+ logger.info("Memcached连接已关闭")
287
+
288
+ # Memcached 不支持分布式锁
289
+ async def acquire_lock(
290
+ self,
291
+ key: str,
292
+ token: str,
293
+ timeout: int,
294
+ blocking: bool,
295
+ blocking_timeout: float | None,
296
+ ) -> bool:
297
+ """获取锁(Memcached 不支持)。"""
298
+ logger.warning("Memcached 不支持分布式锁,请使用 Redis 或 Memory 后端")
299
+ return False
300
+
301
+ async def release_lock(self, key: str, token: str) -> bool:
302
+ """释放锁(Memcached 不支持)。"""
303
+ return False
304
+
305
+
306
+ __all__ = ["MemcachedCache", "MemoryCache"]
@@ -0,0 +1,259 @@
1
+ """Redis 缓存后端实现。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import json
7
+ import pickle
8
+ import time
9
+ from collections.abc import Callable
10
+ from datetime import timedelta
11
+ from typing import TYPE_CHECKING, Any
12
+
13
+ from redis.asyncio import Redis
14
+
15
+ from aury.boot.common.logging import logger
16
+
17
+ from .base import ICache
18
+
19
+ if TYPE_CHECKING:
20
+ from aury.boot.infrastructure.clients.redis import RedisClient
21
+
22
+
23
+ class RedisCache(ICache):
24
+ """Redis缓存实现。
25
+
26
+ 支持两种初始化方式:
27
+ 1. 传入 URL 自行创建连接
28
+ 2. 传入 RedisClient 实例(推荐)
29
+ """
30
+
31
+ def __init__(
32
+ self,
33
+ url: str | None = None,
34
+ *,
35
+ redis_client: RedisClient | None = None,
36
+ serializer: str = "json",
37
+ ):
38
+ """初始化Redis缓存。
39
+
40
+ Args:
41
+ url: Redis连接URL
42
+ redis_client: RedisClient 实例(推荐)
43
+ serializer: 序列化方式(json/pickle)
44
+ """
45
+ self._url = url
46
+ self._redis_client = redis_client
47
+ self._serializer = serializer
48
+ self._redis: Redis | None = None
49
+ self._owns_connection = False # 是否自己拥有连接(需要自己关闭)
50
+
51
+ async def initialize(self) -> None:
52
+ """初始化连接。"""
53
+ # 优先使用 RedisClient
54
+ if self._redis_client is not None:
55
+ self._redis = self._redis_client.connection
56
+ self._owns_connection = False
57
+ logger.info("Redis缓存初始化成功(使用 RedisClient)")
58
+ return
59
+
60
+ # 使用 URL 创建连接
61
+ if self._url:
62
+ try:
63
+ self._redis = Redis.from_url(
64
+ self._url,
65
+ encoding="utf-8",
66
+ decode_responses=False,
67
+ socket_connect_timeout=5,
68
+ socket_timeout=5,
69
+ )
70
+ await self._redis.ping()
71
+ self._owns_connection = True
72
+ logger.info("Redis缓存初始化成功")
73
+ except Exception as exc:
74
+ logger.error(f"Redis连接失败: {exc}")
75
+ raise
76
+ else:
77
+ raise ValueError("Redis缓存需要提供 url 或 redis_client 参数")
78
+
79
+ async def get(self, key: str, default: Any = None) -> Any:
80
+ """获取缓存。"""
81
+ if not self._redis:
82
+ return default
83
+
84
+ try:
85
+ data = await self._redis.get(key)
86
+ if data is None:
87
+ return default
88
+
89
+ # 使用函数式编程处理序列化器
90
+ deserializers: dict[str, Callable[[bytes], Any]] = {
91
+ "json": lambda d: json.loads(d.decode()),
92
+ "pickle": pickle.loads,
93
+ }
94
+
95
+ deserializer = deserializers.get(self._serializer)
96
+ if deserializer:
97
+ return deserializer(data)
98
+ return data.decode()
99
+ except Exception as exc:
100
+ logger.error(f"Redis获取失败: {key}, {exc}")
101
+ return default
102
+
103
+ async def set(
104
+ self,
105
+ key: str,
106
+ value: Any,
107
+ expire: int | timedelta | None = None,
108
+ ) -> bool:
109
+ """设置缓存。"""
110
+ if not self._redis:
111
+ return False
112
+
113
+ try:
114
+ # 使用函数式编程处理序列化器
115
+ serializers: dict[str, Callable[[Any], bytes]] = {
116
+ "json": lambda v: json.dumps(v).encode(),
117
+ "pickle": pickle.dumps,
118
+ }
119
+
120
+ serializer = serializers.get(self._serializer)
121
+ if serializer:
122
+ data = serializer(value)
123
+ else:
124
+ data = str(value).encode()
125
+
126
+ # 转换过期时间
127
+ if isinstance(expire, timedelta):
128
+ expire = int(expire.total_seconds())
129
+
130
+ await self._redis.set(key, data, ex=expire)
131
+ return True
132
+ except Exception as exc:
133
+ logger.error(f"Redis设置失败: {key}, {exc}")
134
+ return False
135
+
136
+ async def delete(self, *keys: str) -> int:
137
+ """删除缓存。"""
138
+ if not self._redis or not keys:
139
+ return 0
140
+
141
+ try:
142
+ return await self._redis.delete(*keys)
143
+ except Exception as exc:
144
+ logger.error(f"Redis删除失败: {keys}, {exc}")
145
+ return 0
146
+
147
+ async def exists(self, *keys: str) -> int:
148
+ """检查缓存是否存在。"""
149
+ if not self._redis or not keys:
150
+ return 0
151
+
152
+ try:
153
+ return await self._redis.exists(*keys)
154
+ except Exception as exc:
155
+ logger.error(f"Redis检查失败: {keys}, {exc}")
156
+ return 0
157
+
158
+ async def clear(self) -> None:
159
+ """清空所有缓存。"""
160
+ if self._redis:
161
+ await self._redis.flushdb()
162
+ logger.info("Redis缓存已清空")
163
+
164
+ async def delete_pattern(self, pattern: str) -> int:
165
+ """按模式删除缓存。
166
+
167
+ Args:
168
+ pattern: 通配符模式,如 "todo:*"
169
+
170
+ Returns:
171
+ int: 删除的键数量
172
+ """
173
+ if not self._redis:
174
+ return 0
175
+
176
+ try:
177
+ # 使用 SCAN 遍历匹配的键(比 KEYS 更安全,不会阻塞)
178
+ count = 0
179
+ cursor = 0
180
+ while True:
181
+ cursor, keys = await self._redis.scan(cursor, match=pattern, count=100)
182
+ if keys:
183
+ count += await self._redis.delete(*keys)
184
+ if cursor == 0:
185
+ break
186
+ logger.debug(f"按模式删除缓存: {pattern}, 删除 {count} 个键")
187
+ return count
188
+ except Exception as exc:
189
+ logger.error(f"Redis模式删除失败: {pattern}, {exc}")
190
+ return 0
191
+
192
+ async def close(self) -> None:
193
+ """关闭连接(仅当自己拥有连接时)。"""
194
+ if self._redis and self._owns_connection:
195
+ await self._redis.close()
196
+ logger.info("Redis连接已关闭")
197
+ self._redis = None
198
+
199
+ @property
200
+ def redis(self) -> Redis | None:
201
+ """获取Redis客户端。"""
202
+ return self._redis
203
+
204
+ # ==================== 分布式锁 ====================
205
+ # TODO: 后续优化考虑:
206
+ # - 看门狗(Watchdog)机制:自动续期,防止业务执行超过锁超时导致提前释放
207
+ # - 可重入锁(Reentrant Lock)
208
+ # - Redlock 算法(多 Redis 实例)
209
+
210
+ async def acquire_lock(
211
+ self,
212
+ key: str,
213
+ token: str,
214
+ timeout: int,
215
+ blocking: bool,
216
+ blocking_timeout: float | None,
217
+ ) -> bool:
218
+ """获取 Redis 分布式锁。"""
219
+ if not self._redis:
220
+ return False
221
+
222
+ start_time = time.monotonic()
223
+
224
+ while True:
225
+ # SET NX EX 原子操作
226
+ acquired = await self._redis.set(key, token, nx=True, ex=timeout)
227
+ if acquired:
228
+ return True
229
+
230
+ if not blocking:
231
+ return False
232
+
233
+ # 检查是否超时
234
+ if blocking_timeout is not None:
235
+ elapsed = time.monotonic() - start_time
236
+ if elapsed >= blocking_timeout:
237
+ return False
238
+
239
+ # 短暂等待后重试
240
+ await asyncio.sleep(0.05)
241
+
242
+ async def release_lock(self, key: str, token: str) -> bool:
243
+ """释放 Redis 锁(Lua 脚本保证原子性)。"""
244
+ if not self._redis:
245
+ return False
246
+
247
+ # Lua 脚本:只有 token 匹配才删除
248
+ script = """
249
+ if redis.call("get", KEYS[1]) == ARGV[1] then
250
+ return redis.call("del", KEYS[1])
251
+ else
252
+ return 0
253
+ end
254
+ """
255
+ result = await self._redis.eval(script, 1, key, token)
256
+ return bool(result)
257
+
258
+
259
+ __all__ = ["RedisCache"]
@@ -159,7 +159,7 @@ class RedisMQ(IMQ):
159
159
  """关闭连接。"""
160
160
  self._consuming = False
161
161
  if self._owns_client and self._client:
162
- await self._client.close()
162
+ await self._client.cleanup()
163
163
  self._client = None
164
164
  logger.debug("Redis 消息队列已关闭")
165
165
 
@@ -420,7 +420,7 @@ class RedisStreamMQ(IMQ):
420
420
  """关闭连接。"""
421
421
  self._consuming = False
422
422
  if self._owns_client and self._client:
423
- await self._client.close()
423
+ await self._client.cleanup()
424
424
  self._client = None
425
425
  logger.debug("Redis Stream 消息队列已关闭")
426
426
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aury-boot
3
- Version: 0.0.36
3
+ Version: 0.0.38
4
4
  Summary: Aury Boot - 基于 FastAPI 生态的企业级 API 开发框架
5
5
  Requires-Python: >=3.13
6
6
  Requires-Dist: alembic>=1.17.2
@@ -1,5 +1,5 @@
1
1
  aury/boot/__init__.py,sha256=pCno-EInnpIBa1OtxNYF-JWf9j95Cd2h6vmu0xqa_-4,1791
2
- aury/boot/_version.py,sha256=0ktbVh2xRI7xnrojV_sDPVhrN753EK8vWN68JQalwWk,706
2
+ aury/boot/_version.py,sha256=vz5IG1ZbpfA63zA7xZI2HHU8kmL9ekzBS0BXtKYIdco,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
@@ -14,7 +14,7 @@ aury/boot/application/app/middlewares.py,sha256=BXe2H14FHzJUVpQM6DZUm-zfZRXSXIi1
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=YxcR75SxdjJznJ1813sK4dhUPJ5ac5ATvGuT6IbNst0,37998
17
+ aury/boot/application/config/settings.py,sha256=JZuLVKH13cuBdlHdtrt7ZZ4d7KD8as5DWBv0d9enHDk,38026
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,7 +47,7 @@ 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=W_eCL3wydWaMSLqTpadREDnzC0w-LGgNnj3IBjuQAfA,32348
50
+ aury/boot/commands/init.py,sha256=6reBpZ5jS4O9QTfXHKt4MCXPn3WcubjUfOtB5tKdy0s,32349
51
51
  aury/boot/commands/pkg.py,sha256=bw0QPptKscNgQ4I1SfSehTio9Q5KrvxgvkYx4tbZ7Vs,14495
52
52
  aury/boot/commands/scheduler.py,sha256=XO3Gq7PqNxXNz5Gw0xNUHa_bEnAKZ9AkzLc062QJ3j8,3669
53
53
  aury/boot/commands/worker.py,sha256=OEvfDiiM_pV3Mj73HKhSm1RNqFPuS125iNM0qNCTHFY,4316
@@ -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=Uj9jNEI9Zn8W061FGFlRaIfAy9IhdassYH6noEjG0z0,662
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=sp5qyzU-SGhgQCobpMW4EXRzpGsEsVdmJvspnKAP4AQ,10059
64
+ aury/boot/commands/templates/project/AGENTS.md.tpl,sha256=KdCqZJeI6cRwjTxX0B2u9fcGQKUi2fJrIjTJBkm3c4U,10063
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
@@ -83,7 +83,7 @@ aury/boot/commands/templates/project/aury_docs/10-storage.md.tpl,sha256=mhe0j0S5
83
83
  aury/boot/commands/templates/project/aury_docs/11-logging.md.tpl,sha256=bwxFCGQsO9cTEbwqJF1xcjsZKP82HRWhIMRUS0c9_ZI,2435
84
84
  aury/boot/commands/templates/project/aury_docs/12-admin.md.tpl,sha256=6z3mN54qP2jtpTFOJBLVexvEv0ZHXYKjncvpZG4yOdw,1883
85
85
  aury/boot/commands/templates/project/aury_docs/13-channel.md.tpl,sha256=aGpf2phQBMRs6Uh1DfjNl06pC_niea91Sm8sTq_NFec,4443
86
- aury/boot/commands/templates/project/aury_docs/14-mq.md.tpl,sha256=4bxLQBbCi0Fue0VQWOPt6acZ5P00BoLkCoLPQe_8k4U,2396
86
+ aury/boot/commands/templates/project/aury_docs/14-mq.md.tpl,sha256=irrKal6y8pPAjifntnOLfRzzllvBQinKMjIjKd-_ANc,4016
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
@@ -93,7 +93,7 @@ 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=SzPRKwN0wO5e1kpjkSwpPJfVmiUDzZkK4Qm-qNsCvVE,2178
96
+ aury/boot/commands/templates/project/env_templates/messaging.tpl,sha256=AgfsXTRnvDySFERoCVop89jsC_h8hzj1sPeq5MczSXM,2462
97
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
@@ -136,11 +136,13 @@ aury/boot/domain/service/base.py,sha256=6sN0nf8r5yUZsE6AcZOiOXFCqzb61oCxTfrWlqjI
136
136
  aury/boot/domain/transaction/__init__.py,sha256=EKnjJ235SYjMCvGIuLVlTdYRzU35RxNMejRGUExYqqE,15488
137
137
  aury/boot/infrastructure/__init__.py,sha256=DDEr_BIL5OyMJjNlI05jGIUrSHn6MPdnW9xnCS4eHfg,2949
138
138
  aury/boot/infrastructure/cache/__init__.py,sha256=G40uCkpJ1jSs2fc_CBDem73iQQzCcp-4GG1WpDJzwaA,658
139
- aury/boot/infrastructure/cache/backends.py,sha256=9QMQ8G9DtZgzVXZ_Ng7n1gXRu-_OQZgw4FHPOfr1qco,13585
140
- aury/boot/infrastructure/cache/base.py,sha256=Yn-h_SGcOoGGZW1unOnz_zgcuHaMKOEmwiUP0P7_pIM,1624
139
+ aury/boot/infrastructure/cache/backends.py,sha256=wh9U2LjlXV22dpV87ID8DL9Rmgztw3yMUrDjJdGgTQw,245
140
+ aury/boot/infrastructure/cache/base.py,sha256=3XA6v_zwsgMSUDN8aG7eu_2-zCnGWF9eeEyVZxxezBU,2621
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
- aury/boot/infrastructure/cache/manager.py,sha256=GGoOgYyIdWKMmhej5cRvEfpNeMN1GaSaU9hc0dy8_sA,12106
143
+ aury/boot/infrastructure/cache/manager.py,sha256=2jlshbO4NqpPxH-8DBiMFNAvWuZUI3atUCsw9GGlzc8,16807
144
+ aury/boot/infrastructure/cache/memory.py,sha256=qGhLKKjGsEUHjVRFMV6A33MB_1iPaKCEEkT6VFrLkQY,9832
145
+ aury/boot/infrastructure/cache/redis.py,sha256=MxLwqnBrPWmkS_AGDq4hKfPlBrF358cq_nKbUlP-JYE,8085
144
146
  aury/boot/infrastructure/channel/__init__.py,sha256=NmjddenZPz1Dcl0glwIF1Xn9gxBzvGvlOlzhV3eEnEQ,664
145
147
  aury/boot/infrastructure/channel/base.py,sha256=TDiP7pXyd2ixiOM3cbxqCSOluGLTkmLCa8pv-KyQ0jo,2941
146
148
  aury/boot/infrastructure/channel/manager.py,sha256=GT6eG6PglduKAr23i1PSmjjTQsALvGGoLjYiQ33aZiw,7488
@@ -190,8 +192,8 @@ aury/boot/infrastructure/mq/base.py,sha256=ld4wtzhO_6y8wJRXL1DagqJiwhd0VQ6MJlJGD
190
192
  aury/boot/infrastructure/mq/manager.py,sha256=Bu4E1Tgz0CzFvJuCS9_fBMj9eAqmXcZp8aFIYhvNUl4,7692
191
193
  aury/boot/infrastructure/mq/backends/__init__.py,sha256=10nggw2V-AzuZ1vvzq_ksoXR4FI3e4BR36EfY49Pek4,200
192
194
  aury/boot/infrastructure/mq/backends/rabbitmq.py,sha256=0NWgPKEwtbmI63EVvKINdfXXDNyOvuOOP9LlBzqH91E,5493
193
- aury/boot/infrastructure/mq/backends/redis.py,sha256=i8KECToIFEZ6CnHyNCk34_xdff5ioK172_knOy6EeUU,5279
194
- aury/boot/infrastructure/mq/backends/redis_stream.py,sha256=hbSX03d0BLshE10GryjyvqybtjDBOS4pQUsNHhQFB-Q,14420
195
+ aury/boot/infrastructure/mq/backends/redis.py,sha256=B89U7mqIceUsCXE4G3u1u6aFM9hv4mmLLwuCYq1T9tQ,5281
196
+ aury/boot/infrastructure/mq/backends/redis_stream.py,sha256=-ZMW4RuQdpmH3hBIqRP7ROyW1gbt8bZ1ZSTrTOynXQQ,14422
195
197
  aury/boot/infrastructure/scheduler/__init__.py,sha256=eTRJ5dSPcKvyFvLVtraoQteXTTDDGwIrmw06J2hoNdA,323
196
198
  aury/boot/infrastructure/scheduler/exceptions.py,sha256=ROltrhSctVWA-6ulnjuYeHAk3ZF-sykDoesuierYzew,634
197
199
  aury/boot/infrastructure/scheduler/manager.py,sha256=OHQOHQlcoN8yFnky4kfuhsEIk39qX6nLZ7xJ51tfg68,23130
@@ -210,7 +212,7 @@ aury/boot/testing/client.py,sha256=KOg1EemuIVsBG68G5y0DjSxZGcIQVdWQ4ASaHE3o1R0,4
210
212
  aury/boot/testing/factory.py,sha256=8GvwX9qIDu0L65gzJMlrWB0xbmJ-7zPHuwk3eECULcg,5185
211
213
  aury/boot/toolkit/__init__.py,sha256=AcyVb9fDf3CaEmJPNkWC4iGv32qCPyk4BuFKSuNiJRQ,334
212
214
  aury/boot/toolkit/http/__init__.py,sha256=zIPmpIZ9Qbqe25VmEr7jixoY2fkRbLm7NkCB9vKpg6I,11039
213
- aury_boot-0.0.36.dist-info/METADATA,sha256=dyV3mpOq5ZzkAUCbQdLt4Bmxw_vyLSyNcuUaJOtF6B8,8694
214
- aury_boot-0.0.36.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
215
- aury_boot-0.0.36.dist-info/entry_points.txt,sha256=f9KXEkDIGc0BGkgBvsNx_HMz9VhDjNxu26q00jUpDwQ,49
216
- aury_boot-0.0.36.dist-info/RECORD,,
215
+ aury_boot-0.0.38.dist-info/METADATA,sha256=jv4ryFTmPLz8qul4nDVB1ju3ftR7oatLmwexC68sM1w,8694
216
+ aury_boot-0.0.38.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
217
+ aury_boot-0.0.38.dist-info/entry_points.txt,sha256=f9KXEkDIGc0BGkgBvsNx_HMz9VhDjNxu26q00jUpDwQ,49
218
+ aury_boot-0.0.38.dist-info/RECORD,,