aury-boot 0.0.2__py3-none-any.whl → 0.0.4__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 (138) hide show
  1. aury/boot/__init__.py +66 -0
  2. aury/boot/_version.py +2 -2
  3. aury/boot/application/__init__.py +120 -0
  4. aury/boot/application/app/__init__.py +39 -0
  5. aury/boot/application/app/base.py +511 -0
  6. aury/boot/application/app/components.py +434 -0
  7. aury/boot/application/app/middlewares.py +101 -0
  8. aury/boot/application/config/__init__.py +44 -0
  9. aury/boot/application/config/settings.py +663 -0
  10. aury/boot/application/constants/__init__.py +19 -0
  11. aury/boot/application/constants/components.py +50 -0
  12. aury/boot/application/constants/scheduler.py +28 -0
  13. aury/boot/application/constants/service.py +29 -0
  14. aury/boot/application/errors/__init__.py +55 -0
  15. aury/boot/application/errors/chain.py +80 -0
  16. aury/boot/application/errors/codes.py +67 -0
  17. aury/boot/application/errors/exceptions.py +238 -0
  18. aury/boot/application/errors/handlers.py +320 -0
  19. aury/boot/application/errors/response.py +120 -0
  20. aury/boot/application/interfaces/__init__.py +76 -0
  21. aury/boot/application/interfaces/egress.py +224 -0
  22. aury/boot/application/interfaces/ingress.py +98 -0
  23. aury/boot/application/middleware/__init__.py +22 -0
  24. aury/boot/application/middleware/logging.py +451 -0
  25. aury/boot/application/migrations/__init__.py +13 -0
  26. aury/boot/application/migrations/manager.py +685 -0
  27. aury/boot/application/migrations/setup.py +237 -0
  28. aury/boot/application/rpc/__init__.py +63 -0
  29. aury/boot/application/rpc/base.py +108 -0
  30. aury/boot/application/rpc/client.py +294 -0
  31. aury/boot/application/rpc/discovery.py +218 -0
  32. aury/boot/application/scheduler/__init__.py +13 -0
  33. aury/boot/application/scheduler/runner.py +123 -0
  34. aury/boot/application/server/__init__.py +296 -0
  35. aury/boot/commands/__init__.py +30 -0
  36. aury/boot/commands/add.py +76 -0
  37. aury/boot/commands/app.py +105 -0
  38. aury/boot/commands/config.py +177 -0
  39. aury/boot/commands/docker.py +367 -0
  40. aury/boot/commands/docs.py +284 -0
  41. aury/boot/commands/generate.py +1277 -0
  42. aury/boot/commands/init.py +892 -0
  43. aury/boot/commands/migrate/__init__.py +37 -0
  44. aury/boot/commands/migrate/app.py +54 -0
  45. aury/boot/commands/migrate/commands.py +303 -0
  46. aury/boot/commands/scheduler.py +124 -0
  47. aury/boot/commands/server/__init__.py +21 -0
  48. aury/boot/commands/server/app.py +541 -0
  49. aury/boot/commands/templates/generate/api.py.tpl +105 -0
  50. aury/boot/commands/templates/generate/model.py.tpl +17 -0
  51. aury/boot/commands/templates/generate/repository.py.tpl +19 -0
  52. aury/boot/commands/templates/generate/schema.py.tpl +29 -0
  53. aury/boot/commands/templates/generate/service.py.tpl +48 -0
  54. aury/boot/commands/templates/project/CLI.md.tpl +92 -0
  55. aury/boot/commands/templates/project/DEVELOPMENT.md.tpl +1397 -0
  56. aury/boot/commands/templates/project/README.md.tpl +111 -0
  57. aury/boot/commands/templates/project/admin_console_init.py.tpl +50 -0
  58. aury/boot/commands/templates/project/config.py.tpl +30 -0
  59. aury/boot/commands/templates/project/conftest.py.tpl +26 -0
  60. aury/boot/commands/templates/project/env.example.tpl +213 -0
  61. aury/boot/commands/templates/project/gitignore.tpl +128 -0
  62. aury/boot/commands/templates/project/main.py.tpl +41 -0
  63. aury/boot/commands/templates/project/modules/api.py.tpl +19 -0
  64. aury/boot/commands/templates/project/modules/exceptions.py.tpl +84 -0
  65. aury/boot/commands/templates/project/modules/schedules.py.tpl +18 -0
  66. aury/boot/commands/templates/project/modules/tasks.py.tpl +20 -0
  67. aury/boot/commands/worker.py +143 -0
  68. aury/boot/common/__init__.py +35 -0
  69. aury/boot/common/exceptions/__init__.py +114 -0
  70. aury/boot/common/i18n/__init__.py +16 -0
  71. aury/boot/common/i18n/translator.py +272 -0
  72. aury/boot/common/logging/__init__.py +716 -0
  73. aury/boot/contrib/__init__.py +10 -0
  74. aury/boot/contrib/admin_console/__init__.py +18 -0
  75. aury/boot/contrib/admin_console/auth.py +137 -0
  76. aury/boot/contrib/admin_console/discovery.py +69 -0
  77. aury/boot/contrib/admin_console/install.py +172 -0
  78. aury/boot/contrib/admin_console/utils.py +44 -0
  79. aury/boot/domain/__init__.py +79 -0
  80. aury/boot/domain/exceptions/__init__.py +132 -0
  81. aury/boot/domain/models/__init__.py +51 -0
  82. aury/boot/domain/models/base.py +69 -0
  83. aury/boot/domain/models/mixins.py +135 -0
  84. aury/boot/domain/models/models.py +96 -0
  85. aury/boot/domain/pagination/__init__.py +279 -0
  86. aury/boot/domain/repository/__init__.py +23 -0
  87. aury/boot/domain/repository/impl.py +423 -0
  88. aury/boot/domain/repository/interceptors.py +47 -0
  89. aury/boot/domain/repository/interface.py +106 -0
  90. aury/boot/domain/repository/query_builder.py +348 -0
  91. aury/boot/domain/service/__init__.py +11 -0
  92. aury/boot/domain/service/base.py +73 -0
  93. aury/boot/domain/transaction/__init__.py +404 -0
  94. aury/boot/infrastructure/__init__.py +104 -0
  95. aury/boot/infrastructure/cache/__init__.py +31 -0
  96. aury/boot/infrastructure/cache/backends.py +348 -0
  97. aury/boot/infrastructure/cache/base.py +68 -0
  98. aury/boot/infrastructure/cache/exceptions.py +37 -0
  99. aury/boot/infrastructure/cache/factory.py +94 -0
  100. aury/boot/infrastructure/cache/manager.py +274 -0
  101. aury/boot/infrastructure/database/__init__.py +39 -0
  102. aury/boot/infrastructure/database/config.py +71 -0
  103. aury/boot/infrastructure/database/exceptions.py +44 -0
  104. aury/boot/infrastructure/database/manager.py +317 -0
  105. aury/boot/infrastructure/database/query_tools/__init__.py +164 -0
  106. aury/boot/infrastructure/database/strategies/__init__.py +198 -0
  107. aury/boot/infrastructure/di/__init__.py +15 -0
  108. aury/boot/infrastructure/di/container.py +393 -0
  109. aury/boot/infrastructure/events/__init__.py +33 -0
  110. aury/boot/infrastructure/events/bus.py +362 -0
  111. aury/boot/infrastructure/events/config.py +52 -0
  112. aury/boot/infrastructure/events/consumer.py +134 -0
  113. aury/boot/infrastructure/events/middleware.py +51 -0
  114. aury/boot/infrastructure/events/models.py +63 -0
  115. aury/boot/infrastructure/monitoring/__init__.py +529 -0
  116. aury/boot/infrastructure/scheduler/__init__.py +19 -0
  117. aury/boot/infrastructure/scheduler/exceptions.py +37 -0
  118. aury/boot/infrastructure/scheduler/manager.py +478 -0
  119. aury/boot/infrastructure/storage/__init__.py +38 -0
  120. aury/boot/infrastructure/storage/base.py +164 -0
  121. aury/boot/infrastructure/storage/exceptions.py +37 -0
  122. aury/boot/infrastructure/storage/factory.py +88 -0
  123. aury/boot/infrastructure/tasks/__init__.py +24 -0
  124. aury/boot/infrastructure/tasks/config.py +45 -0
  125. aury/boot/infrastructure/tasks/constants.py +37 -0
  126. aury/boot/infrastructure/tasks/exceptions.py +37 -0
  127. aury/boot/infrastructure/tasks/manager.py +490 -0
  128. aury/boot/testing/__init__.py +24 -0
  129. aury/boot/testing/base.py +122 -0
  130. aury/boot/testing/client.py +163 -0
  131. aury/boot/testing/factory.py +154 -0
  132. aury/boot/toolkit/__init__.py +21 -0
  133. aury/boot/toolkit/http/__init__.py +367 -0
  134. {aury_boot-0.0.2.dist-info → aury_boot-0.0.4.dist-info}/METADATA +3 -2
  135. aury_boot-0.0.4.dist-info/RECORD +137 -0
  136. aury_boot-0.0.2.dist-info/RECORD +0 -5
  137. {aury_boot-0.0.2.dist-info → aury_boot-0.0.4.dist-info}/WHEEL +0 -0
  138. {aury_boot-0.0.2.dist-info → aury_boot-0.0.4.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,348 @@
1
+ """缓存后端实现。
2
+
3
+ 提供 Redis、Memory、Memcached 等缓存后端的实现。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import asyncio
9
+ from collections.abc import Callable
10
+ from datetime import timedelta
11
+ import json
12
+ import pickle
13
+ from typing import Any
14
+
15
+ from redis.asyncio import Redis
16
+
17
+ from aury.boot.common.logging import logger
18
+
19
+ from .base import ICache
20
+
21
+
22
+ class RedisCache(ICache):
23
+ """Redis缓存实现。"""
24
+
25
+ def __init__(self, url: str, *, serializer: str = "json"):
26
+ """初始化Redis缓存。
27
+
28
+ Args:
29
+ url: Redis连接URL
30
+ serializer: 序列化方式(json/pickle)
31
+ """
32
+ self._url = url
33
+ self._serializer = serializer
34
+ self._redis: Redis | None = None
35
+
36
+ async def initialize(self) -> None:
37
+ """初始化连接。"""
38
+ try:
39
+ self._redis = Redis.from_url(
40
+ self._url,
41
+ encoding="utf-8",
42
+ decode_responses=False,
43
+ socket_connect_timeout=5,
44
+ socket_timeout=5,
45
+ )
46
+ await self._redis.ping()
47
+ logger.info("Redis缓存初始化成功")
48
+ except Exception as exc:
49
+ logger.error(f"Redis连接失败: {exc}")
50
+ raise
51
+
52
+ async def get(self, key: str, default: Any = None) -> Any:
53
+ """获取缓存。"""
54
+ if not self._redis:
55
+ return default
56
+
57
+ try:
58
+ data = await self._redis.get(key)
59
+ if data is None:
60
+ return default
61
+
62
+ # 使用函数式编程处理序列化器
63
+ deserializers: dict[str, Callable[[bytes], Any]] = {
64
+ "json": lambda d: json.loads(d.decode()),
65
+ "pickle": pickle.loads,
66
+ }
67
+
68
+ deserializer = deserializers.get(self._serializer)
69
+ if deserializer:
70
+ return deserializer(data)
71
+ return data.decode()
72
+ except Exception as exc:
73
+ logger.error(f"Redis获取失败: {key}, {exc}")
74
+ return default
75
+
76
+ async def set(
77
+ self,
78
+ key: str,
79
+ value: Any,
80
+ expire: int | timedelta | None = None,
81
+ ) -> bool:
82
+ """设置缓存。"""
83
+ if not self._redis:
84
+ return False
85
+
86
+ try:
87
+ # 使用函数式编程处理序列化器
88
+ serializers: dict[str, Callable[[Any], bytes]] = {
89
+ "json": lambda v: json.dumps(v).encode(),
90
+ "pickle": pickle.dumps,
91
+ }
92
+
93
+ serializer = serializers.get(self._serializer)
94
+ if serializer:
95
+ data = serializer(value)
96
+ else:
97
+ data = str(value).encode()
98
+
99
+ # 转换过期时间
100
+ if isinstance(expire, timedelta):
101
+ expire = int(expire.total_seconds())
102
+
103
+ await self._redis.set(key, data, ex=expire)
104
+ return True
105
+ except Exception as exc:
106
+ logger.error(f"Redis设置失败: {key}, {exc}")
107
+ return False
108
+
109
+ async def delete(self, *keys: str) -> int:
110
+ """删除缓存。"""
111
+ if not self._redis or not keys:
112
+ return 0
113
+
114
+ try:
115
+ return await self._redis.delete(*keys)
116
+ except Exception as exc:
117
+ logger.error(f"Redis删除失败: {keys}, {exc}")
118
+ return 0
119
+
120
+ async def exists(self, *keys: str) -> int:
121
+ """检查缓存是否存在。"""
122
+ if not self._redis or not keys:
123
+ return 0
124
+
125
+ try:
126
+ return await self._redis.exists(*keys)
127
+ except Exception as exc:
128
+ logger.error(f"Redis检查失败: {keys}, {exc}")
129
+ return 0
130
+
131
+ async def clear(self) -> None:
132
+ """清空所有缓存。"""
133
+ if self._redis:
134
+ await self._redis.flushdb()
135
+ logger.info("Redis缓存已清空")
136
+
137
+ async def close(self) -> None:
138
+ """关闭连接。"""
139
+ if self._redis:
140
+ await self._redis.close()
141
+ logger.info("Redis连接已关闭")
142
+
143
+ @property
144
+ def redis(self) -> Redis | None:
145
+ """获取Redis客户端。"""
146
+ return self._redis
147
+
148
+
149
+ class MemoryCache(ICache):
150
+ """内存缓存实现。"""
151
+
152
+ def __init__(self, max_size: int = 1000):
153
+ """初始化内存缓存。
154
+
155
+ Args:
156
+ max_size: 最大缓存项数
157
+ """
158
+ self._max_size = max_size
159
+ self._cache: dict[str, tuple[Any, float | None]] = {}
160
+ self._lock = asyncio.Lock()
161
+
162
+ async def get(self, key: str, default: Any = None) -> Any:
163
+ """获取缓存。"""
164
+ async with self._lock:
165
+ if key not in self._cache:
166
+ return default
167
+
168
+ value, expire_at = self._cache[key]
169
+
170
+ # 检查过期
171
+ if expire_at is not None and asyncio.get_event_loop().time() > expire_at:
172
+ del self._cache[key]
173
+ return default
174
+
175
+ return value
176
+
177
+ async def set(
178
+ self,
179
+ key: str,
180
+ value: Any,
181
+ expire: int | timedelta | None = None,
182
+ ) -> bool:
183
+ """设置缓存。"""
184
+ async with self._lock:
185
+ # 转换过期时间
186
+ expire_at = None
187
+ if expire:
188
+ if isinstance(expire, timedelta):
189
+ expire_seconds = expire.total_seconds()
190
+ else:
191
+ expire_seconds = expire
192
+ expire_at = asyncio.get_event_loop().time() + expire_seconds
193
+
194
+ # 如果超出容量,删除最旧的
195
+ if len(self._cache) >= self._max_size and key not in self._cache:
196
+ # 简单策略:删除第一个
197
+ first_key = next(iter(self._cache))
198
+ del self._cache[first_key]
199
+
200
+ self._cache[key] = (value, expire_at)
201
+ return True
202
+
203
+ async def delete(self, *keys: str) -> int:
204
+ """删除缓存。"""
205
+ async with self._lock:
206
+ count = 0
207
+ for key in keys:
208
+ if key in self._cache:
209
+ del self._cache[key]
210
+ count += 1
211
+ return count
212
+
213
+ async def exists(self, *keys: str) -> int:
214
+ """检查缓存是否存在。"""
215
+ async with self._lock:
216
+ count = 0
217
+ for key in keys:
218
+ if key in self._cache:
219
+ _value, expire_at = self._cache[key]
220
+ # 检查是否过期
221
+ if expire_at is None or asyncio.get_event_loop().time() <= expire_at:
222
+ count += 1
223
+ return count
224
+
225
+ async def clear(self) -> None:
226
+ """清空所有缓存。"""
227
+ async with self._lock:
228
+ self._cache.clear()
229
+ logger.info("内存缓存已清空")
230
+
231
+ async def close(self) -> None:
232
+ """关闭连接(内存缓存无需关闭)。"""
233
+ await self.clear()
234
+
235
+ async def size(self) -> int:
236
+ """获取缓存大小。"""
237
+ return len(self._cache)
238
+
239
+
240
+ class MemcachedCache(ICache):
241
+ """Memcached缓存实现(可选)。"""
242
+
243
+ def __init__(self, servers: list[str]):
244
+ """初始化Memcached缓存。
245
+
246
+ Args:
247
+ servers: Memcached服务器列表,如 ["127.0.0.1:11211"]
248
+ """
249
+ self._servers = servers
250
+ self._client = None
251
+
252
+ async def initialize(self) -> None:
253
+ """初始化连接。"""
254
+ try:
255
+ # 需要安装 python-memcached 或 aiomcache
256
+ try:
257
+ import aiomcache
258
+ self._client = aiomcache.Client(
259
+ self._servers[0].split(":")[0],
260
+ int(self._servers[0].split(":")[1]) if ":" in self._servers[0] else 11211,
261
+ )
262
+ logger.info("Memcached缓存初始化成功")
263
+ except ImportError:
264
+ logger.error("请安装 aiomcache: pip install aiomcache")
265
+ raise
266
+ except Exception as exc:
267
+ logger.error(f"Memcached连接失败: {exc}")
268
+ raise
269
+
270
+ async def get(self, key: str, default: Any = None) -> Any:
271
+ """获取缓存。"""
272
+ if not self._client:
273
+ return default
274
+
275
+ try:
276
+ data = await self._client.get(key.encode())
277
+ if data is None:
278
+ return default
279
+ return json.loads(data.decode())
280
+ except Exception as exc:
281
+ logger.error(f"Memcached获取失败: {key}, {exc}")
282
+ return default
283
+
284
+ async def set(
285
+ self,
286
+ key: str,
287
+ value: Any,
288
+ expire: int | timedelta | None = None,
289
+ ) -> bool:
290
+ """设置缓存。"""
291
+ if not self._client:
292
+ return False
293
+
294
+ try:
295
+ if isinstance(expire, timedelta):
296
+ expire = int(expire.total_seconds())
297
+
298
+ data = json.dumps(value).encode()
299
+ return await self._client.set(key.encode(), data, exptime=expire or 0)
300
+ except Exception as exc:
301
+ logger.error(f"Memcached设置失败: {key}, {exc}")
302
+ return False
303
+
304
+ async def delete(self, *keys: str) -> int:
305
+ """删除缓存。"""
306
+ if not self._client or not keys:
307
+ return 0
308
+
309
+ count = 0
310
+ for key in keys:
311
+ try:
312
+ if await self._client.delete(key.encode()):
313
+ count += 1
314
+ except Exception as exc:
315
+ logger.error(f"Memcached删除失败: {key}, {exc}")
316
+ return count
317
+
318
+ async def exists(self, *keys: str) -> int:
319
+ """检查缓存是否存在。"""
320
+ if not self._client or not keys:
321
+ return 0
322
+
323
+ count = 0
324
+ for key in keys:
325
+ try:
326
+ if await self._client.get(key.encode()) is not None:
327
+ count += 1
328
+ except Exception:
329
+ pass
330
+ return count
331
+
332
+ async def clear(self) -> None:
333
+ """清空所有缓存(Memcached不支持)。"""
334
+ logger.warning("Memcached不支持清空所有缓存")
335
+
336
+ async def close(self) -> None:
337
+ """关闭连接。"""
338
+ if self._client:
339
+ self._client.close()
340
+ logger.info("Memcached连接已关闭")
341
+
342
+
343
+ __all__ = [
344
+ "MemcachedCache",
345
+ "MemoryCache",
346
+ "RedisCache",
347
+ ]
348
+
@@ -0,0 +1,68 @@
1
+ """缓存系统基础接口和类型定义。
2
+
3
+ 提供缓存接口和枚举类型。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from abc import ABC, abstractmethod
9
+ from datetime import timedelta
10
+ from enum import Enum
11
+ from typing import Any
12
+
13
+
14
+ class CacheBackend(str, Enum):
15
+ """缓存后端类型。"""
16
+
17
+ REDIS = "redis"
18
+ MEMORY = "memory"
19
+ MEMCACHED = "memcached"
20
+
21
+
22
+ class ICache(ABC):
23
+ """缓存接口。
24
+
25
+ 所有缓存后端必须实现此接口。
26
+ """
27
+
28
+ @abstractmethod
29
+ async def get(self, key: str, default: Any = None) -> Any:
30
+ """获取缓存。"""
31
+ pass
32
+
33
+ @abstractmethod
34
+ async def set(
35
+ self,
36
+ key: str,
37
+ value: Any,
38
+ expire: int | timedelta | None = None,
39
+ ) -> bool:
40
+ """设置缓存。"""
41
+ pass
42
+
43
+ @abstractmethod
44
+ async def delete(self, *keys: str) -> int:
45
+ """删除缓存。"""
46
+ pass
47
+
48
+ @abstractmethod
49
+ async def exists(self, *keys: str) -> int:
50
+ """检查缓存是否存在。"""
51
+ pass
52
+
53
+ @abstractmethod
54
+ async def clear(self) -> None:
55
+ """清空所有缓存。"""
56
+ pass
57
+
58
+ @abstractmethod
59
+ async def close(self) -> None:
60
+ """关闭连接。"""
61
+ pass
62
+
63
+
64
+ __all__ = [
65
+ "CacheBackend",
66
+ "ICache",
67
+ ]
68
+
@@ -0,0 +1,37 @@
1
+ """缓存相关异常定义。
2
+
3
+ Infrastructure 层异常,继承自 FoundationError。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from aury.boot.common.exceptions import FoundationError
9
+
10
+
11
+ class CacheError(FoundationError):
12
+ """缓存相关错误基类。
13
+
14
+ 所有缓存相关的异常都应该继承此类。
15
+ """
16
+
17
+ pass
18
+
19
+
20
+ class CacheMissError(CacheError):
21
+ """缓存未命中错误(可选,通常不抛出)。"""
22
+
23
+ pass
24
+
25
+
26
+ class CacheBackendError(CacheError):
27
+ """缓存后端错误。"""
28
+
29
+ pass
30
+
31
+
32
+ __all__ = [
33
+ "CacheBackendError",
34
+ "CacheError",
35
+ "CacheMissError",
36
+ ]
37
+
@@ -0,0 +1,94 @@
1
+ """缓存工厂 - 注册机制。
2
+
3
+ 通过注册机制支持多种缓存后端。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from typing import ClassVar
9
+
10
+ from aury.boot.common.logging import logger
11
+
12
+ from .backends import (
13
+ MemcachedCache,
14
+ MemoryCache,
15
+ RedisCache,
16
+ )
17
+ from .base import ICache
18
+
19
+
20
+ class CacheFactory:
21
+ """缓存工厂 - 注册机制。
22
+
23
+ 类似Flask-Cache的设计,通过注册机制支持多种后端。
24
+
25
+ 使用示例:
26
+ # 注册后端
27
+ CacheFactory.register("redis", RedisCache)
28
+ CacheFactory.register("memory", MemoryCache)
29
+
30
+ # 创建缓存实例
31
+ cache = await CacheFactory.create("redis", url="redis://localhost:6379")
32
+ cache = await CacheFactory.create("memory", max_size=1000)
33
+ """
34
+
35
+ _backends: ClassVar[dict[str, type[ICache]]] = {}
36
+
37
+ @classmethod
38
+ def register(cls, name: str, backend_class: type[ICache]) -> None:
39
+ """注册缓存后端。
40
+
41
+ Args:
42
+ name: 后端名称
43
+ backend_class: 后端类
44
+ """
45
+ cls._backends[name] = backend_class
46
+ logger.debug(f"注册缓存后端: {name} -> {backend_class.__name__}")
47
+
48
+ @classmethod
49
+ async def create(cls, backend_name: str, **config) -> ICache:
50
+ """创建缓存实例。
51
+
52
+ Args:
53
+ backend_name: 后端名称
54
+ **config: 配置参数
55
+
56
+ Returns:
57
+ ICache: 缓存实例
58
+
59
+ Raises:
60
+ ValueError: 后端未注册
61
+ """
62
+ if backend_name not in cls._backends:
63
+ available = ", ".join(cls._backends.keys())
64
+ raise ValueError(
65
+ f"缓存后端 '{backend_name}' 未注册。"
66
+ f"可用后端: {available}"
67
+ )
68
+
69
+ backend_class = cls._backends[backend_name]
70
+ instance = backend_class(**config)
71
+
72
+ # 如果后端需要初始化
73
+ if hasattr(instance, "initialize"):
74
+ await instance.initialize()
75
+
76
+ logger.info(f"创建缓存实例: {backend_name}")
77
+ return instance
78
+
79
+ @classmethod
80
+ def get_registered(cls) -> list[str]:
81
+ """获取已注册的后端名称。"""
82
+ return list(cls._backends.keys())
83
+
84
+
85
+ # 注册默认后端
86
+ CacheFactory.register("redis", RedisCache)
87
+ CacheFactory.register("memory", MemoryCache)
88
+ CacheFactory.register("memcached", MemcachedCache)
89
+
90
+
91
+ __all__ = [
92
+ "CacheFactory",
93
+ ]
94
+