aury-boot 0.0.4__py3-none-any.whl → 0.0.7__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 (122) hide show
  1. aury/boot/__init__.py +2 -2
  2. aury/boot/_version.py +2 -2
  3. aury/boot/application/__init__.py +60 -36
  4. aury/boot/application/adapter/__init__.py +112 -0
  5. aury/boot/application/adapter/base.py +511 -0
  6. aury/boot/application/adapter/config.py +242 -0
  7. aury/boot/application/adapter/decorators.py +259 -0
  8. aury/boot/application/adapter/exceptions.py +202 -0
  9. aury/boot/application/adapter/http.py +325 -0
  10. aury/boot/application/app/__init__.py +12 -8
  11. aury/boot/application/app/base.py +12 -0
  12. aury/boot/application/app/components.py +137 -44
  13. aury/boot/application/app/middlewares.py +9 -4
  14. aury/boot/application/app/startup.py +249 -0
  15. aury/boot/application/config/__init__.py +36 -1
  16. aury/boot/application/config/multi_instance.py +216 -0
  17. aury/boot/application/config/settings.py +398 -149
  18. aury/boot/application/constants/components.py +6 -0
  19. aury/boot/application/errors/handlers.py +17 -3
  20. aury/boot/application/middleware/logging.py +21 -120
  21. aury/boot/application/rpc/__init__.py +2 -2
  22. aury/boot/commands/__init__.py +30 -10
  23. aury/boot/commands/app.py +131 -1
  24. aury/boot/commands/docs.py +104 -17
  25. aury/boot/commands/generate.py +22 -22
  26. aury/boot/commands/init.py +68 -17
  27. aury/boot/commands/server/app.py +2 -3
  28. aury/boot/commands/templates/project/AGENTS.md.tpl +221 -0
  29. aury/boot/commands/templates/project/README.md.tpl +2 -2
  30. aury/boot/commands/templates/project/aury_docs/00-overview.md.tpl +59 -0
  31. aury/boot/commands/templates/project/aury_docs/01-model.md.tpl +184 -0
  32. aury/boot/commands/templates/project/aury_docs/02-repository.md.tpl +206 -0
  33. aury/boot/commands/templates/project/aury_docs/03-service.md.tpl +398 -0
  34. aury/boot/commands/templates/project/aury_docs/04-schema.md.tpl +95 -0
  35. aury/boot/commands/templates/project/aury_docs/05-api.md.tpl +116 -0
  36. aury/boot/commands/templates/project/aury_docs/06-exception.md.tpl +118 -0
  37. aury/boot/commands/templates/project/aury_docs/07-cache.md.tpl +122 -0
  38. aury/boot/commands/templates/project/aury_docs/08-scheduler.md.tpl +32 -0
  39. aury/boot/commands/templates/project/aury_docs/09-tasks.md.tpl +38 -0
  40. aury/boot/commands/templates/project/aury_docs/10-storage.md.tpl +115 -0
  41. aury/boot/commands/templates/project/aury_docs/11-logging.md.tpl +131 -0
  42. aury/boot/commands/templates/project/aury_docs/12-admin.md.tpl +56 -0
  43. aury/boot/commands/templates/project/aury_docs/13-channel.md.tpl +104 -0
  44. aury/boot/commands/templates/project/aury_docs/14-mq.md.tpl +102 -0
  45. aury/boot/commands/templates/project/aury_docs/15-events.md.tpl +147 -0
  46. aury/boot/commands/templates/project/aury_docs/16-adapter.md.tpl +403 -0
  47. aury/boot/commands/templates/project/{CLI.md.tpl → aury_docs/99-cli.md.tpl} +19 -19
  48. aury/boot/commands/templates/project/config.py.tpl +10 -10
  49. aury/boot/commands/templates/project/env_templates/_header.tpl +10 -0
  50. aury/boot/commands/templates/project/env_templates/admin.tpl +49 -0
  51. aury/boot/commands/templates/project/env_templates/cache.tpl +14 -0
  52. aury/boot/commands/templates/project/env_templates/database.tpl +22 -0
  53. aury/boot/commands/templates/project/env_templates/log.tpl +18 -0
  54. aury/boot/commands/templates/project/env_templates/messaging.tpl +46 -0
  55. aury/boot/commands/templates/project/env_templates/rpc.tpl +28 -0
  56. aury/boot/commands/templates/project/env_templates/scheduler.tpl +18 -0
  57. aury/boot/commands/templates/project/env_templates/service.tpl +18 -0
  58. aury/boot/commands/templates/project/env_templates/storage.tpl +38 -0
  59. aury/boot/commands/templates/project/env_templates/third_party.tpl +43 -0
  60. aury/boot/commands/templates/project/modules/tasks.py.tpl +1 -1
  61. aury/boot/common/logging/__init__.py +26 -674
  62. aury/boot/common/logging/context.py +132 -0
  63. aury/boot/common/logging/decorators.py +118 -0
  64. aury/boot/common/logging/format.py +315 -0
  65. aury/boot/common/logging/setup.py +214 -0
  66. aury/boot/contrib/admin_console/auth.py +2 -3
  67. aury/boot/contrib/admin_console/install.py +1 -1
  68. aury/boot/domain/models/mixins.py +48 -1
  69. aury/boot/domain/pagination/__init__.py +94 -0
  70. aury/boot/domain/repository/impl.py +1 -1
  71. aury/boot/domain/repository/interface.py +1 -1
  72. aury/boot/domain/transaction/__init__.py +8 -9
  73. aury/boot/infrastructure/__init__.py +86 -29
  74. aury/boot/infrastructure/cache/backends.py +102 -18
  75. aury/boot/infrastructure/cache/base.py +12 -0
  76. aury/boot/infrastructure/cache/manager.py +153 -91
  77. aury/boot/infrastructure/channel/__init__.py +24 -0
  78. aury/boot/infrastructure/channel/backends/__init__.py +9 -0
  79. aury/boot/infrastructure/channel/backends/memory.py +83 -0
  80. aury/boot/infrastructure/channel/backends/redis.py +88 -0
  81. aury/boot/infrastructure/channel/base.py +92 -0
  82. aury/boot/infrastructure/channel/manager.py +203 -0
  83. aury/boot/infrastructure/clients/__init__.py +22 -0
  84. aury/boot/infrastructure/clients/rabbitmq/__init__.py +9 -0
  85. aury/boot/infrastructure/clients/rabbitmq/config.py +46 -0
  86. aury/boot/infrastructure/clients/rabbitmq/manager.py +288 -0
  87. aury/boot/infrastructure/clients/redis/__init__.py +28 -0
  88. aury/boot/infrastructure/clients/redis/config.py +51 -0
  89. aury/boot/infrastructure/clients/redis/manager.py +264 -0
  90. aury/boot/infrastructure/database/config.py +7 -16
  91. aury/boot/infrastructure/database/manager.py +16 -38
  92. aury/boot/infrastructure/events/__init__.py +18 -21
  93. aury/boot/infrastructure/events/backends/__init__.py +11 -0
  94. aury/boot/infrastructure/events/backends/memory.py +86 -0
  95. aury/boot/infrastructure/events/backends/rabbitmq.py +193 -0
  96. aury/boot/infrastructure/events/backends/redis.py +162 -0
  97. aury/boot/infrastructure/events/base.py +127 -0
  98. aury/boot/infrastructure/events/manager.py +224 -0
  99. aury/boot/infrastructure/mq/__init__.py +24 -0
  100. aury/boot/infrastructure/mq/backends/__init__.py +9 -0
  101. aury/boot/infrastructure/mq/backends/rabbitmq.py +179 -0
  102. aury/boot/infrastructure/mq/backends/redis.py +167 -0
  103. aury/boot/infrastructure/mq/base.py +143 -0
  104. aury/boot/infrastructure/mq/manager.py +239 -0
  105. aury/boot/infrastructure/scheduler/manager.py +7 -3
  106. aury/boot/infrastructure/storage/__init__.py +9 -9
  107. aury/boot/infrastructure/storage/base.py +17 -5
  108. aury/boot/infrastructure/storage/factory.py +0 -1
  109. aury/boot/infrastructure/tasks/__init__.py +2 -2
  110. aury/boot/infrastructure/tasks/config.py +5 -13
  111. aury/boot/infrastructure/tasks/manager.py +55 -33
  112. {aury_boot-0.0.4.dist-info → aury_boot-0.0.7.dist-info}/METADATA +20 -2
  113. aury_boot-0.0.7.dist-info/RECORD +197 -0
  114. aury/boot/commands/templates/project/DEVELOPMENT.md.tpl +0 -1397
  115. aury/boot/commands/templates/project/env.example.tpl +0 -213
  116. aury/boot/infrastructure/events/bus.py +0 -362
  117. aury/boot/infrastructure/events/config.py +0 -52
  118. aury/boot/infrastructure/events/consumer.py +0 -134
  119. aury/boot/infrastructure/events/models.py +0 -63
  120. aury_boot-0.0.4.dist-info/RECORD +0 -137
  121. {aury_boot-0.0.4.dist-info → aury_boot-0.0.7.dist-info}/WHEEL +0 -0
  122. {aury_boot-0.0.4.dist-info → aury_boot-0.0.7.dist-info}/entry_points.txt +0 -0
@@ -9,23 +9,33 @@
9
9
  from __future__ import annotations
10
10
 
11
11
  from pathlib import Path
12
- from typing import Literal
12
+ from typing import Any, Literal
13
13
 
14
14
  from dotenv import load_dotenv
15
- from pydantic import Field
15
+ from pydantic import BaseModel, Field
16
16
  from pydantic_settings import BaseSettings, SettingsConfigDict
17
17
 
18
+ from .multi_instance import MultiInstanceConfigLoader, MultiInstanceSettings
19
+
18
20
 
19
21
  def _load_env_file(env_file: str | Path) -> bool:
20
22
  """加载 .env 文件到环境变量。"""
21
23
  return load_dotenv(env_file, override=True)
22
24
 
23
25
 
24
- class DatabaseSettings(BaseSettings):
25
- """数据库配置。
26
+ # =============================================================================
27
+ # 多实例配置基类
28
+ # =============================================================================
29
+
30
+
31
+ class DatabaseInstanceConfig(MultiInstanceSettings):
32
+ """数据库实例配置。
26
33
 
27
- 环境变量前缀: DATABASE_
28
- 示例: DATABASE_URL, DATABASE_ECHO, DATABASE_POOL_SIZE
34
+ 环境变量格式: DATABASE__{INSTANCE}__{FIELD}
35
+ 示例:
36
+ DATABASE__DEFAULT__URL=postgresql://main...
37
+ DATABASE__DEFAULT__POOL_SIZE=10
38
+ DATABASE__ANALYTICS__URL=postgresql://analytics...
29
39
  """
30
40
 
31
41
  url: str = Field(
@@ -56,23 +66,170 @@ class DatabaseSettings(BaseSettings):
56
66
  default=True,
57
67
  description="是否在获取连接前进行 PING"
58
68
  )
69
+
70
+
71
+ class CacheInstanceConfig(MultiInstanceSettings):
72
+ """缓存实例配置。
59
73
 
60
- model_config = SettingsConfigDict(
61
- env_prefix="DATABASE_",
62
- case_sensitive=False,
74
+ 环境变量格式: CACHE__{INSTANCE}__{FIELD}
75
+ 示例:
76
+ CACHE__DEFAULT__BACKEND=redis
77
+ CACHE__DEFAULT__URL=redis://localhost:6379/0
78
+ CACHE__LOCAL__BACKEND=memory
79
+ CACHE__LOCAL__MAX_SIZE=5000
80
+ """
81
+
82
+ backend: str = Field(
83
+ default="memory",
84
+ description="缓存后端 (memory/redis/memcached)"
85
+ )
86
+ url: str | None = Field(
87
+ default=None,
88
+ description="缓存服务 URL"
89
+ )
90
+ max_size: int = Field(
91
+ default=1000,
92
+ description="内存缓存最大大小"
93
+ )
94
+
95
+
96
+ class StorageInstanceConfig(MultiInstanceSettings):
97
+ """对象存储实例配置。
98
+
99
+ 环境变量格式: STORAGE__{INSTANCE}__{FIELD}
100
+ 示例:
101
+ STORAGE__DEFAULT__BACKEND=s3
102
+ STORAGE__DEFAULT__BUCKET=main-bucket
103
+ STORAGE__BACKUP__BACKEND=local
104
+ STORAGE__BACKUP__BASE_PATH=/backup
105
+ """
106
+
107
+ backend: Literal["local", "s3", "oss", "cos"] = Field(
108
+ default="local",
109
+ description="存储后端"
110
+ )
111
+ # S3 配置
112
+ access_key_id: str | None = Field(default=None)
113
+ access_key_secret: str | None = Field(default=None)
114
+ endpoint: str | None = Field(default=None)
115
+ region: str | None = Field(default=None)
116
+ bucket_name: str | None = Field(default=None)
117
+ # 本地存储
118
+ base_path: str = Field(default="./storage")
119
+
120
+
121
+ class ChannelInstanceConfig(MultiInstanceSettings):
122
+ """通道实例配置。
123
+
124
+ 环境变量格式: CHANNEL__{INSTANCE}__{FIELD}
125
+ 示例:
126
+ CHANNEL__DEFAULT__BACKEND=memory
127
+ CHANNEL__SHARED__BACKEND=redis
128
+ CHANNEL__SHARED__URL=redis://localhost:6379/3
129
+ """
130
+
131
+ backend: str = Field(
132
+ default="memory",
133
+ description="通道后端 (memory/redis)"
134
+ )
135
+ url: str | None = Field(
136
+ default=None,
137
+ description="Redis URL(当 backend=redis 时需要)"
138
+ )
139
+
140
+
141
+ class MQInstanceConfig(MultiInstanceSettings):
142
+ """消息队列实例配置。
143
+
144
+ 环境变量格式: MQ__{INSTANCE}__{FIELD}
145
+ 示例:
146
+ MQ__DEFAULT__BACKEND=redis
147
+ MQ__DEFAULT__URL=redis://localhost:6379/4
148
+ """
149
+
150
+ backend: str = Field(
151
+ default="redis",
152
+ description="消息队列后端 (redis/rabbitmq)"
153
+ )
154
+ url: str | None = Field(
155
+ default=None,
156
+ description="连接 URL"
157
+ )
158
+
159
+
160
+ class EventInstanceConfig(MultiInstanceSettings):
161
+ """事件总线实例配置。
162
+
163
+ 环境变量格式: EVENT__{INSTANCE}__{FIELD}
164
+ 示例:
165
+ EVENT__DEFAULT__BACKEND=memory
166
+ EVENT__DISTRIBUTED__BACKEND=redis
167
+ EVENT__DISTRIBUTED__URL=redis://localhost:6379/5
168
+ """
169
+
170
+ backend: str = Field(
171
+ default="memory",
172
+ description="事件后端 (memory/redis/rabbitmq)"
173
+ )
174
+ url: str | None = Field(
175
+ default=None,
176
+ description="连接 URL"
63
177
  )
64
178
 
65
179
 
66
- class CacheSettings(BaseSettings):
180
+ # =============================================================================
181
+ # 单实例配置
182
+ # =============================================================================
183
+
184
+
185
+ class DatabaseSettings(BaseModel):
186
+ """数据库配置(单实例)。
187
+
188
+ 环境变量格式: DATABASE__{FIELD}
189
+ 示例: DATABASE__URL, DATABASE__POOL_SIZE
190
+ 多实例格式: DATABASE__{INSTANCE}__{FIELD}
191
+ """
192
+
193
+ url: str = Field(
194
+ default="sqlite+aiosqlite:///./app.db",
195
+ description="数据库连接字符串"
196
+ )
197
+ echo: bool = Field(
198
+ default=False,
199
+ description="是否输出 SQL 语句"
200
+ )
201
+ pool_size: int = Field(
202
+ default=5,
203
+ description="数据库连接池大小"
204
+ )
205
+ max_overflow: int = Field(
206
+ default=10,
207
+ description="连接池最大溢出连接数"
208
+ )
209
+ pool_recycle: int = Field(
210
+ default=3600,
211
+ description="连接回收时间(秒)"
212
+ )
213
+ pool_timeout: int = Field(
214
+ default=30,
215
+ description="获取连接超时时间(秒)"
216
+ )
217
+ pool_pre_ping: bool = Field(
218
+ default=True,
219
+ description="是否在获取连接前进行 PING"
220
+ )
221
+
222
+
223
+ class CacheSettings(BaseModel):
67
224
  """缓存配置。
68
225
 
69
- 环境变量前缀: CACHE_
70
- 示例: CACHE_TYPE, CACHE_URL, CACHE_MAX_SIZE
226
+ 环境变量格式: CACHE__{FIELD}
227
+ 示例: CACHE__TYPE, CACHE__URL, CACHE__MAX_SIZE
71
228
 
72
229
  支持的缓存类型:
73
230
  - memory: 内存缓存(默认,无需 URL)
74
- - redis: Redis 缓存(需要设置 CACHE_URL
75
- - memcached: Memcached 缓存(需要设置 CACHE_URL
231
+ - redis: Redis 缓存(需要设置 CACHE__URL
232
+ - memcached: Memcached 缓存(需要设置 CACHE__URL
76
233
  """
77
234
 
78
235
  cache_type: str = Field(
@@ -87,22 +244,14 @@ class CacheSettings(BaseSettings):
87
244
  default=1000,
88
245
  description="内存缓存最大大小"
89
246
  )
90
-
91
- model_config = SettingsConfigDict(
92
- env_prefix="CACHE_",
93
- case_sensitive=False,
94
- )
95
247
 
96
248
 
97
- class StorageSettings(BaseSettings):
249
+ class StorageSettings(BaseModel):
98
250
  """对象存储组件接入配置(Application 层)。
99
251
 
100
- 说明:
101
- - Application 层负责从 env/.env 读取配置(快速接入组件)
102
- - Infrastructure 层的 storage 仅接受 Pydantic(BaseModel) 的配置对象,不读取 env
103
-
104
- 环境变量前缀:STORAGE_
105
- """
252
+ 环境变量格式: STORAGE__{FIELD}
253
+ 示例: STORAGE__TYPE, STORAGE__BUCKET_NAME
254
+ """
106
255
 
107
256
  enabled: bool = Field(default=True, description="是否启用存储组件")
108
257
 
@@ -129,22 +278,16 @@ class StorageSettings(BaseSettings):
129
278
  # local
130
279
  base_path: str = Field(default="./storage", description="本地存储基础目录")
131
280
 
132
- model_config = SettingsConfigDict(
133
- env_prefix="STORAGE_",
134
- case_sensitive=False,
135
- extra="ignore",
136
- )
137
-
138
281
 
139
- class ServerSettings(BaseSettings):
282
+ class ServerSettings(BaseModel):
140
283
  """服务器配置。
141
284
 
142
- 环境变量前缀: SERVER_
143
- 示例: SERVER_HOST, SERVER_PORT, SERVER_RELOAD
285
+ 环境变量格式: SERVER__{FIELD}
286
+ 示例: SERVER__HOST, SERVER__PORT, SERVER__RELOAD
144
287
  """
145
288
 
146
289
  host: str = Field(
147
- default="127.0.0.1",
290
+ default="0.0.0.0",
148
291
  description="服务器监听地址"
149
292
  )
150
293
  port: int = Field(
@@ -159,18 +302,13 @@ class ServerSettings(BaseSettings):
159
302
  default=1,
160
303
  description="工作进程数"
161
304
  )
162
-
163
- model_config = SettingsConfigDict(
164
- env_prefix="SERVER_",
165
- case_sensitive=False,
166
- )
167
305
 
168
306
 
169
- class CORSSettings(BaseSettings):
307
+ class CORSSettings(BaseModel):
170
308
  """CORS配置。
171
309
 
172
- 环境变量前缀: CORS_
173
- 示例: CORS_ORIGINS, CORS_ALLOW_CREDENTIALS, CORS_ALLOW_METHODS
310
+ 环境变量格式: CORS__{FIELD}
311
+ 示例: CORS__ORIGINS, CORS__ALLOW_CREDENTIALS, CORS__ALLOW_METHODS
174
312
  """
175
313
 
176
314
  origins: list[str] = Field(
@@ -189,18 +327,13 @@ class CORSSettings(BaseSettings):
189
327
  default=["*"],
190
328
  description="允许的CORS头"
191
329
  )
192
-
193
- model_config = SettingsConfigDict(
194
- env_prefix="CORS_",
195
- case_sensitive=False,
196
- )
197
330
 
198
331
 
199
- class LogSettings(BaseSettings):
332
+ class LogSettings(BaseModel):
200
333
  """日志配置。
201
334
 
202
- 环境变量前缀: LOG_
203
- 示例: LOG_LEVEL, LOG_DIR, LOG_ROTATION_TIME, LOG_RETENTION_DAYS
335
+ 环境变量格式: LOG__{FIELD}
336
+ 示例: LOG__LEVEL, LOG__DIR, LOG__ROTATION_TIME, LOG__RETENTION_DAYS
204
337
  """
205
338
 
206
339
  level: str = Field(
@@ -239,24 +372,19 @@ class LogSettings(BaseSettings):
239
372
  default=False,
240
373
  description="是否记录 WebSocket 消息内容(注意性能和敏感数据)"
241
374
  )
242
-
243
- model_config = SettingsConfigDict(
244
- env_prefix="LOG_",
245
- case_sensitive=False,
246
- )
247
375
 
248
376
 
249
- class ServiceSettings(BaseSettings):
377
+ class ServiceSettings(BaseModel):
250
378
  """服务配置。
251
379
 
252
- 环境变量前缀: SERVICE_
253
- 示例: SERVICE_NAME, SERVICE_TYPE
380
+ 环境变量格式: SERVICE__{FIELD}
381
+ 示例: SERVICE__NAME, SERVICE__TYPE
254
382
 
255
383
  服务类型说明:
256
- - api: 运行 API 服务(SCHEDULER_ENABLED 决定是否同时运行调度器)
384
+ - api: 运行 API 服务(SCHEDULER__ENABLED 决定是否同时运行调度器)
257
385
  - worker: 运行任务队列 Worker(处理异步任务)
258
386
 
259
- 独立调度器通过 `aury scheduler` 命令运行,不需要配置 SERVICE_TYPE
387
+ 独立调度器通过 `aury scheduler` 命令运行,不需要配置 SERVICE__TYPE
260
388
  """
261
389
 
262
390
  name: str = Field(
@@ -268,21 +396,16 @@ class ServiceSettings(BaseSettings):
268
396
  description="服务类型(api/worker)"
269
397
  )
270
398
 
271
- model_config = SettingsConfigDict(
272
- env_prefix="SERVICE_",
273
- case_sensitive=False,
274
- )
275
-
276
399
 
277
- class SchedulerSettings(BaseSettings):
400
+ class SchedulerSettings(BaseModel):
278
401
  """调度器配置。
279
402
 
280
- 环境变量前缀: SCHEDULER_
281
- 示例: SCHEDULER_ENABLED, SCHEDULER_SCHEDULE_MODULES
403
+ 环境变量格式: SCHEDULER__{FIELD}
404
+ 示例: SCHEDULER__ENABLED, SCHEDULER__SCHEDULE_MODULES
282
405
 
283
- 仅在 SERVICE_TYPE=api 时有效:
284
- - SCHEDULER_ENABLED=true: API 服务同时运行内嵌调度器(默认)
285
- - SCHEDULER_ENABLED=false: 只运行 API,不启动调度器
406
+ 仅在 SERVICE__TYPE=api 时有效:
407
+ - SCHEDULER__ENABLED=true: API 服务同时运行内嵌调度器(默认)
408
+ - SCHEDULER__ENABLED=false: 只运行 API,不启动调度器
286
409
 
287
410
  独立调度器通过 `aury scheduler` 命令运行,不需要此配置。
288
411
  """
@@ -295,18 +418,13 @@ class SchedulerSettings(BaseSettings):
295
418
  default_factory=list,
296
419
  description="定时任务模块列表。为空时自动发现 schedules 模块"
297
420
  )
298
-
299
- model_config = SettingsConfigDict(
300
- env_prefix="SCHEDULER_",
301
- case_sensitive=False,
302
- )
303
421
 
304
422
 
305
- class TaskSettings(BaseSettings):
423
+ class TaskSettings(BaseModel):
306
424
  """任务队列配置。
307
425
 
308
- 环境变量前缀: TASK_
309
- 示例: TASK_BROKER_URL, TASK_MAX_RETRIES
426
+ 环境变量格式: TASK__{FIELD}
427
+ 示例: TASK__BROKER_URL, TASK__MAX_RETRIES
310
428
  """
311
429
 
312
430
  broker_url: str | None = Field(
@@ -321,18 +439,13 @@ class TaskSettings(BaseSettings):
321
439
  default=3600,
322
440
  description="任务超时时间(秒)"
323
441
  )
324
-
325
- model_config = SettingsConfigDict(
326
- env_prefix="TASK_",
327
- case_sensitive=False,
328
- )
329
442
 
330
443
 
331
- class EventSettings(BaseSettings):
444
+ class EventSettings(BaseModel):
332
445
  """事件总线配置。
333
446
 
334
- 环境变量前缀: EVENT_
335
- 示例: EVENT_BROKER_URL, EVENT_EXCHANGE_NAME
447
+ 环境变量格式: EVENT__{FIELD}
448
+ 示例: EVENT__BROKER_URL, EVENT__EXCHANGE_NAME
336
449
  """
337
450
 
338
451
  broker_url: str | None = Field(
@@ -343,18 +456,51 @@ class EventSettings(BaseSettings):
343
456
  default="aury.events",
344
457
  description="事件交换机名称"
345
458
  )
459
+
460
+
461
+ class MessageQueueSettings(BaseModel):
462
+ """消息队列配置。
346
463
 
347
- model_config = SettingsConfigDict(
348
- env_prefix="EVENT_",
349
- case_sensitive=False,
464
+ 环境变量格式: MQ__{FIELD}
465
+ 示例: MQ__BROKER_URL, MQ__DEFAULT_QUEUE, MQ__SERIALIZER
466
+
467
+ 与 Task(任务队列)的区别:
468
+ - Task: 基于 Dramatiq,用于异步任务处理(API + Worker 模式)
469
+ - MQ: 通用消息队列,用于服务间通信、事件驱动架构
470
+
471
+ 支持的后端(通过 Kombu):
472
+ - Redis: redis://localhost:6379/0
473
+ - RabbitMQ: amqp://guest:guest@localhost:5672//
474
+ - Amazon SQS: sqs://
475
+ """
476
+
477
+ enabled: bool = Field(
478
+ default=False,
479
+ description="是否启用消息队列组件"
480
+ )
481
+ broker_url: str | None = Field(
482
+ default=None,
483
+ description="消息队列代理 URL"
484
+ )
485
+ default_queue: str = Field(
486
+ default="default",
487
+ description="默认队列名称"
488
+ )
489
+ serializer: str = Field(
490
+ default="json",
491
+ description="序列化方式(json/pickle/msgpack)"
492
+ )
493
+ prefetch_count: int = Field(
494
+ default=1,
495
+ description="预取消息数量"
350
496
  )
351
497
 
352
498
 
353
- class MigrationSettings(BaseSettings):
499
+ class MigrationSettings(BaseModel):
354
500
  """数据库迁移配置。
355
501
 
356
- 环境变量前缀: MIGRATION_
357
- 示例: MIGRATION_CONFIG_PATH, MIGRATION_SCRIPT_LOCATION, MIGRATION_MODEL_MODULES
502
+ 环境变量格式: MIGRATION__{FIELD}
503
+ 示例: MIGRATION__CONFIG_PATH, MIGRATION__SCRIPT_LOCATION, MIGRATION__MODEL_MODULES
358
504
  """
359
505
 
360
506
  config_path: str = Field(
@@ -377,20 +523,15 @@ class MigrationSettings(BaseSettings):
377
523
  default=True,
378
524
  description="是否自动创建迁移配置和目录"
379
525
  )
380
-
381
- model_config = SettingsConfigDict(
382
- env_prefix="MIGRATION_",
383
- case_sensitive=False,
384
- )
385
526
 
386
527
 
387
- class RPCClientSettings(BaseSettings):
528
+ class RPCClientSettings(BaseModel):
388
529
  """RPC 客户端调用配置。
389
530
 
390
531
  用于配置客户端调用其他服务时的行为。
391
532
 
392
- 环境变量前缀: RPC_CLIENT_
393
- 示例: RPC_CLIENT_SERVICES, RPC_CLIENT_TIMEOUT, RPC_CLIENT_RETRY_TIMES, RPC_CLIENT_DNS_SCHEME
533
+ 环境变量格式: RPC_CLIENT__{FIELD}
534
+ 示例: RPC_CLIENT__SERVICES, RPC_CLIENT__TIMEOUT, RPC_CLIENT__RETRY_TIMES
394
535
  """
395
536
 
396
537
  services: dict[str, str] = Field(
@@ -417,20 +558,15 @@ class RPCClientSettings(BaseSettings):
417
558
  default=True,
418
559
  description="是否在配置中找不到时使用 DNS 解析(K8s/Docker Compose 自动 DNS)"
419
560
  )
420
-
421
- model_config = SettingsConfigDict(
422
- env_prefix="RPC_CLIENT_",
423
- case_sensitive=False,
424
- )
425
561
 
426
562
 
427
- class RPCServiceSettings(BaseSettings):
563
+ class RPCServiceSettings(BaseModel):
428
564
  """RPC 服务注册配置。
429
565
 
430
566
  用于配置当前服务注册到服务注册中心时的信息。
431
567
 
432
- 环境变量前缀: RPC_SERVICE_
433
- 示例: RPC_SERVICE_NAME, RPC_SERVICE_URL, RPC_SERVICE_HEALTH_CHECK_URL
568
+ 环境变量格式: RPC_SERVICE__{FIELD}
569
+ 示例: RPC_SERVICE__NAME, RPC_SERVICE__URL, RPC_SERVICE__HEALTH_CHECK_URL
434
570
  """
435
571
 
436
572
  name: str | None = Field(
@@ -453,21 +589,16 @@ class RPCServiceSettings(BaseSettings):
453
589
  default=None,
454
590
  description="服务注册中心地址(如果使用外部注册中心)"
455
591
  )
456
-
457
- model_config = SettingsConfigDict(
458
- env_prefix="RPC_SERVICE_",
459
- case_sensitive=False,
460
- )
461
592
 
462
593
 
463
- class HealthCheckSettings(BaseSettings):
594
+ class HealthCheckSettings(BaseModel):
464
595
  """健康检查配置。
465
596
 
466
597
  用于配置 Aury 框架的默认健康检查端点。
467
598
  注意:此配置仅用于框架内置的健康检查端点,不影响服务自身的健康检查端点。
468
599
 
469
- 环境变量前缀: HEALTH_CHECK_
470
- 示例: HEALTH_CHECK_PATH, HEALTH_CHECK_ENABLED
600
+ 环境变量格式: HEALTH_CHECK__{FIELD}
601
+ 示例: HEALTH_CHECK__PATH, HEALTH_CHECK__ENABLED
471
602
  """
472
603
 
473
604
  path: str = Field(
@@ -478,22 +609,17 @@ class HealthCheckSettings(BaseSettings):
478
609
  default=True,
479
610
  description="是否启用 Aury 默认健康检查端点"
480
611
  )
481
-
482
- model_config = SettingsConfigDict(
483
- env_prefix="HEALTH_CHECK_",
484
- case_sensitive=False,
485
- )
486
612
 
487
613
 
488
- class AdminAuthSettings(BaseSettings):
614
+ class AdminAuthSettings(BaseModel):
489
615
  """管理后台认证配置。
490
616
 
491
- 环境变量前缀: ADMIN_AUTH_
492
- 示例: ADMIN_AUTH_MODE, ADMIN_AUTH_SECRET_KEY, ADMIN_AUTH_BASIC_USERNAME
617
+ 作为 ADMIN 配置的子配置,环境变量格式: ADMIN__AUTH__{FIELD}
618
+ 示例: ADMIN__AUTH__MODE, ADMIN__AUTH__SECRET_KEY, ADMIN__AUTH__BASIC_USERNAME
493
619
 
494
620
  说明:
495
621
  - 内置模式仅保证 basic / bearer 开箱即用
496
- - jwt/custom 推荐由用户自定义 backend 实现(见 ADMIN_AUTH_BACKEND)
622
+ - jwt/custom 推荐由用户自定义 backend 实现
497
623
  """
498
624
 
499
625
  mode: Literal["none", "basic", "bearer", "jwt", "custom"] = Field(
@@ -520,17 +646,13 @@ class AdminAuthSettings(BaseSettings):
520
646
  description='自定义认证后端导入路径,如 "yourpkg.admin_auth:backend"',
521
647
  )
522
648
 
523
- model_config = SettingsConfigDict(
524
- env_prefix="ADMIN_AUTH_",
525
- case_sensitive=False,
526
- )
527
649
 
528
-
529
- class AdminConsoleSettings(BaseSettings):
650
+ class AdminConsoleSettings(BaseModel):
530
651
  """SQLAdmin 管理后台配置。
531
652
 
532
- 环境变量前缀: ADMIN_
533
- 示例: ADMIN_ENABLED, ADMIN_PATH, ADMIN_DATABASE_URL
653
+ 环境变量格式: ADMIN__{FIELD}
654
+ 示例: ADMIN__ENABLED, ADMIN__PATH, ADMIN__DATABASE_URL
655
+ 嵌套配置: ADMIN__AUTH__{FIELD}
534
656
  """
535
657
 
536
658
  enabled: bool = Field(default=False, description="是否启用管理后台")
@@ -554,11 +676,6 @@ class AdminConsoleSettings(BaseSettings):
554
676
 
555
677
  auth: AdminAuthSettings = Field(default_factory=AdminAuthSettings, description="管理后台认证配置")
556
678
 
557
- model_config = SettingsConfigDict(
558
- env_prefix="ADMIN_",
559
- case_sensitive=False,
560
- )
561
-
562
679
 
563
680
  class BaseConfig(BaseSettings):
564
681
  """基础配置类。
@@ -566,9 +683,34 @@ class BaseConfig(BaseSettings):
566
683
  所有应用配置的基类,提供通用配置项。
567
684
  初始化时自动从 .env 文件加载环境变量,然后由 pydantic-settings 读取环境变量。
568
685
 
686
+ 环境变量格式:
687
+ 使用双下划线 (__) 作为层级分隔符:
688
+ {SECTION}__{FIELD}=value
689
+ {SECTION}__{NESTED}__{FIELD}=value
690
+
691
+ 单实例示例:
692
+ SERVER__HOST=0.0.0.0
693
+ SERVER__PORT=8000
694
+ DATABASE__URL=postgresql://...
695
+ LOG__LEVEL=INFO
696
+
697
+ 多实例示例:
698
+ DATABASE__DEFAULT__URL=postgresql://main...
699
+ DATABASE__ANALYTICS__URL=postgresql://analytics...
700
+ CACHE__DEFAULT__BACKEND=redis
701
+ CACHE__REDIS__URL=redis://localhost:6379/1
702
+
569
703
  注意:Application 层配置完全独立,不依赖 Infrastructure 层。
570
704
  """
571
705
 
706
+ # 多实例配置缓存
707
+ _databases: dict[str, DatabaseInstanceConfig] | None = None
708
+ _caches: dict[str, CacheInstanceConfig] | None = None
709
+ _storages: dict[str, StorageInstanceConfig] | None = None
710
+ _channels: dict[str, ChannelInstanceConfig] | None = None
711
+ _mqs: dict[str, MQInstanceConfig] | None = None
712
+ _events: dict[str, EventInstanceConfig] | None = None
713
+
572
714
  def __init__(self, _env_file: str | Path = ".env", **kwargs) -> None:
573
715
  """初始化配置。
574
716
 
@@ -597,13 +739,8 @@ class BaseConfig(BaseSettings):
597
739
  admin: AdminConsoleSettings = Field(default_factory=AdminConsoleSettings)
598
740
 
599
741
  # ========== 数据与缓存 ==========
600
- # 数据库配置
601
742
  database: DatabaseSettings = Field(default_factory=DatabaseSettings)
602
-
603
- # 缓存配置
604
743
  cache: CacheSettings = Field(default_factory=CacheSettings)
605
-
606
- # 对象存储配置(接入用;storage SDK 本身不读取 env)
607
744
  storage: StorageSettings = Field(default_factory=StorageSettings)
608
745
 
609
746
  # 迁移配置
@@ -617,10 +754,7 @@ class BaseConfig(BaseSettings):
617
754
  scheduler: SchedulerSettings = Field(default_factory=SchedulerSettings)
618
755
 
619
756
  # ========== 异步与事件 ==========
620
- # 任务队列配置
621
757
  task: TaskSettings = Field(default_factory=TaskSettings)
622
-
623
- # 事件总线配置
624
758
  event: EventSettings = Field(default_factory=EventSettings)
625
759
 
626
760
  # ========== 微服务通信 ==========
@@ -633,8 +767,114 @@ class BaseConfig(BaseSettings):
633
767
  model_config = SettingsConfigDict(
634
768
  case_sensitive=False,
635
769
  extra="ignore",
770
+ env_nested_delimiter="__",
636
771
  )
637
772
 
773
+ # ========== 多实例配置访问方法 ==========
774
+
775
+ def get_databases(self) -> dict[str, DatabaseInstanceConfig]:
776
+ """获取所有数据库实例配置。
777
+
778
+ 从环境变量解析 DATABASE__{INSTANCE}__{FIELD} 格式的配置。
779
+ 如果没有配置多实例,返回从单实例配置转换的 default 实例。
780
+ """
781
+ if self._databases is None:
782
+ loader = MultiInstanceConfigLoader("DATABASE", DatabaseInstanceConfig)
783
+ self._databases = loader.load()
784
+ if not self._databases:
785
+ self._databases = {
786
+ "default": DatabaseInstanceConfig(
787
+ url=self.database.url,
788
+ echo=self.database.echo,
789
+ pool_size=self.database.pool_size,
790
+ max_overflow=self.database.max_overflow,
791
+ pool_recycle=self.database.pool_recycle,
792
+ pool_timeout=self.database.pool_timeout,
793
+ pool_pre_ping=self.database.pool_pre_ping,
794
+ )
795
+ }
796
+ return self._databases
797
+
798
+ def get_caches(self) -> dict[str, CacheInstanceConfig]:
799
+ """获取所有缓存实例配置。
800
+
801
+ 从环境变量解析 CACHE__{INSTANCE}__{FIELD} 格式的配置。
802
+ 如果没有配置多实例,返回从单实例配置转换的 default 实例。
803
+ """
804
+ if self._caches is None:
805
+ loader = MultiInstanceConfigLoader("CACHE", CacheInstanceConfig)
806
+ self._caches = loader.load()
807
+ if not self._caches:
808
+ self._caches = {
809
+ "default": CacheInstanceConfig(
810
+ backend=self.cache.cache_type,
811
+ url=self.cache.url,
812
+ max_size=self.cache.max_size,
813
+ )
814
+ }
815
+ return self._caches
816
+
817
+ def get_storages(self) -> dict[str, StorageInstanceConfig]:
818
+ """获取所有存储实例配置。
819
+
820
+ 从环境变量解析 STORAGE__{INSTANCE}__{FIELD} 格式的配置。
821
+ 如果没有配置多实例,返回从单实例配置转换的 default 实例。
822
+ """
823
+ if self._storages is None:
824
+ loader = MultiInstanceConfigLoader("STORAGE", StorageInstanceConfig)
825
+ self._storages = loader.load()
826
+ if not self._storages:
827
+ self._storages = {
828
+ "default": StorageInstanceConfig(
829
+ backend=self.storage.type,
830
+ access_key_id=self.storage.access_key_id,
831
+ access_key_secret=self.storage.access_key_secret,
832
+ endpoint=self.storage.endpoint,
833
+ region=self.storage.region,
834
+ bucket_name=self.storage.bucket_name,
835
+ base_path=self.storage.base_path,
836
+ )
837
+ }
838
+ return self._storages
839
+
840
+ def get_channels(self) -> dict[str, ChannelInstanceConfig]:
841
+ """获取所有通道实例配置。
842
+
843
+ 从环境变量解析 CHANNEL__{INSTANCE}__{FIELD} 格式的配置。
844
+ """
845
+ if self._channels is None:
846
+ loader = MultiInstanceConfigLoader("CHANNEL", ChannelInstanceConfig)
847
+ self._channels = loader.load()
848
+ return self._channels
849
+
850
+ def get_mqs(self) -> dict[str, MQInstanceConfig]:
851
+ """获取所有消息队列实例配置。
852
+
853
+ 从环境变量解析 MQ__{INSTANCE}__{FIELD} 格式的配置。
854
+ """
855
+ if self._mqs is None:
856
+ loader = MultiInstanceConfigLoader("MQ", MQInstanceConfig)
857
+ self._mqs = loader.load()
858
+ return self._mqs
859
+
860
+ def get_events(self) -> dict[str, EventInstanceConfig]:
861
+ """获取所有事件总线实例配置。
862
+
863
+ 从环境变量解析 EVENT__{INSTANCE}__{FIELD} 格式的配置。
864
+ 如果没有配置多实例,返回从单实例配置转换的 default 实例。
865
+ """
866
+ if self._events is None:
867
+ loader = MultiInstanceConfigLoader("EVENT", EventInstanceConfig)
868
+ self._events = loader.load()
869
+ if not self._events and self.event.broker_url:
870
+ self._events = {
871
+ "default": EventInstanceConfig(
872
+ backend="redis" if "redis" in (self.event.broker_url or "") else "rabbitmq",
873
+ url=self.event.broker_url,
874
+ )
875
+ }
876
+ return self._events
877
+
638
878
  @property
639
879
  def is_production(self) -> bool:
640
880
  """是否为生产环境。"""
@@ -642,21 +882,30 @@ class BaseConfig(BaseSettings):
642
882
 
643
883
 
644
884
  __all__ = [
885
+ # 配置类
645
886
  "AdminAuthSettings",
646
887
  "AdminConsoleSettings",
647
888
  "BaseConfig",
648
889
  "CORSSettings",
890
+ # 多实例配置类
891
+ "CacheInstanceConfig",
649
892
  "CacheSettings",
893
+ "ChannelInstanceConfig",
894
+ "DatabaseInstanceConfig",
650
895
  "DatabaseSettings",
896
+ "EventInstanceConfig",
651
897
  "EventSettings",
652
898
  "HealthCheckSettings",
653
899
  "LogSettings",
900
+ "MQInstanceConfig",
901
+ "MessageQueueSettings",
654
902
  "MigrationSettings",
655
903
  "RPCClientSettings",
656
904
  "RPCServiceSettings",
657
905
  "SchedulerSettings",
658
906
  "ServerSettings",
659
907
  "ServiceSettings",
908
+ "StorageInstanceConfig",
660
909
  "StorageSettings",
661
910
  "TaskSettings",
662
911
  ]