aury-boot 0.0.5__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 (49) hide show
  1. aury/boot/_version.py +2 -2
  2. aury/boot/application/__init__.py +15 -0
  3. aury/boot/application/adapter/__init__.py +112 -0
  4. aury/boot/application/adapter/base.py +511 -0
  5. aury/boot/application/adapter/config.py +242 -0
  6. aury/boot/application/adapter/decorators.py +259 -0
  7. aury/boot/application/adapter/exceptions.py +202 -0
  8. aury/boot/application/adapter/http.py +325 -0
  9. aury/boot/application/app/middlewares.py +7 -4
  10. aury/boot/application/config/multi_instance.py +42 -26
  11. aury/boot/application/config/settings.py +111 -191
  12. aury/boot/application/middleware/logging.py +14 -1
  13. aury/boot/commands/generate.py +22 -22
  14. aury/boot/commands/init.py +41 -9
  15. aury/boot/commands/templates/project/AGENTS.md.tpl +8 -4
  16. aury/boot/commands/templates/project/aury_docs/01-model.md.tpl +17 -16
  17. aury/boot/commands/templates/project/aury_docs/11-logging.md.tpl +82 -43
  18. aury/boot/commands/templates/project/aury_docs/12-admin.md.tpl +14 -14
  19. aury/boot/commands/templates/project/aury_docs/13-channel.md.tpl +40 -28
  20. aury/boot/commands/templates/project/aury_docs/14-mq.md.tpl +9 -9
  21. aury/boot/commands/templates/project/aury_docs/15-events.md.tpl +8 -8
  22. aury/boot/commands/templates/project/aury_docs/16-adapter.md.tpl +403 -0
  23. aury/boot/commands/templates/project/aury_docs/99-cli.md.tpl +19 -19
  24. aury/boot/commands/templates/project/config.py.tpl +10 -10
  25. aury/boot/commands/templates/project/env_templates/_header.tpl +10 -0
  26. aury/boot/commands/templates/project/env_templates/admin.tpl +49 -0
  27. aury/boot/commands/templates/project/env_templates/cache.tpl +14 -0
  28. aury/boot/commands/templates/project/env_templates/database.tpl +22 -0
  29. aury/boot/commands/templates/project/env_templates/log.tpl +18 -0
  30. aury/boot/commands/templates/project/env_templates/messaging.tpl +46 -0
  31. aury/boot/commands/templates/project/env_templates/rpc.tpl +28 -0
  32. aury/boot/commands/templates/project/env_templates/scheduler.tpl +18 -0
  33. aury/boot/commands/templates/project/env_templates/service.tpl +18 -0
  34. aury/boot/commands/templates/project/env_templates/storage.tpl +38 -0
  35. aury/boot/commands/templates/project/env_templates/third_party.tpl +43 -0
  36. aury/boot/common/logging/__init__.py +26 -674
  37. aury/boot/common/logging/context.py +132 -0
  38. aury/boot/common/logging/decorators.py +118 -0
  39. aury/boot/common/logging/format.py +315 -0
  40. aury/boot/common/logging/setup.py +214 -0
  41. aury/boot/infrastructure/database/config.py +6 -14
  42. aury/boot/infrastructure/tasks/config.py +5 -13
  43. aury/boot/infrastructure/tasks/manager.py +8 -4
  44. aury/boot/testing/base.py +2 -2
  45. {aury_boot-0.0.5.dist-info → aury_boot-0.0.7.dist-info}/METADATA +2 -1
  46. {aury_boot-0.0.5.dist-info → aury_boot-0.0.7.dist-info}/RECORD +48 -27
  47. aury/boot/commands/templates/project/env.example.tpl +0 -281
  48. {aury_boot-0.0.5.dist-info → aury_boot-0.0.7.dist-info}/WHEEL +0 -0
  49. {aury_boot-0.0.5.dist-info → aury_boot-0.0.7.dist-info}/entry_points.txt +0 -0
@@ -12,7 +12,7 @@ from pathlib import Path
12
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
18
  from .multi_instance import MultiInstanceConfigLoader, MultiInstanceSettings
@@ -31,11 +31,11 @@ def _load_env_file(env_file: str | Path) -> bool:
31
31
  class DatabaseInstanceConfig(MultiInstanceSettings):
32
32
  """数据库实例配置。
33
33
 
34
- 环境变量格式: DATABASE_{INSTANCE}_{FIELD}
34
+ 环境变量格式: DATABASE__{INSTANCE}__{FIELD}
35
35
  示例:
36
- DATABASE_DEFAULT_URL=postgresql://main...
37
- DATABASE_DEFAULT_POOL_SIZE=10
38
- DATABASE_ANALYTICS_URL=postgresql://analytics...
36
+ DATABASE__DEFAULT__URL=postgresql://main...
37
+ DATABASE__DEFAULT__POOL_SIZE=10
38
+ DATABASE__ANALYTICS__URL=postgresql://analytics...
39
39
  """
40
40
 
41
41
  url: str = Field(
@@ -71,12 +71,12 @@ class DatabaseInstanceConfig(MultiInstanceSettings):
71
71
  class CacheInstanceConfig(MultiInstanceSettings):
72
72
  """缓存实例配置。
73
73
 
74
- 环境变量格式: CACHE_{INSTANCE}_{FIELD}
74
+ 环境变量格式: CACHE__{INSTANCE}__{FIELD}
75
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
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
80
  """
81
81
 
82
82
  backend: str = Field(
@@ -96,12 +96,12 @@ class CacheInstanceConfig(MultiInstanceSettings):
96
96
  class StorageInstanceConfig(MultiInstanceSettings):
97
97
  """对象存储实例配置。
98
98
 
99
- 环境变量格式: STORAGE_{INSTANCE}_{FIELD}
99
+ 环境变量格式: STORAGE__{INSTANCE}__{FIELD}
100
100
  示例:
101
- STORAGE_DEFAULT_BACKEND=s3
102
- STORAGE_DEFAULT_BUCKET=main-bucket
103
- STORAGE_BACKUP_BACKEND=local
104
- STORAGE_BACKUP_BASE_PATH=/backup
101
+ STORAGE__DEFAULT__BACKEND=s3
102
+ STORAGE__DEFAULT__BUCKET=main-bucket
103
+ STORAGE__BACKUP__BACKEND=local
104
+ STORAGE__BACKUP__BASE_PATH=/backup
105
105
  """
106
106
 
107
107
  backend: Literal["local", "s3", "oss", "cos"] = Field(
@@ -121,11 +121,11 @@ class StorageInstanceConfig(MultiInstanceSettings):
121
121
  class ChannelInstanceConfig(MultiInstanceSettings):
122
122
  """通道实例配置。
123
123
 
124
- 环境变量格式: CHANNEL_{INSTANCE}_{FIELD}
124
+ 环境变量格式: CHANNEL__{INSTANCE}__{FIELD}
125
125
  示例:
126
- CHANNEL_DEFAULT_BACKEND=memory
127
- CHANNEL_SHARED_BACKEND=redis
128
- CHANNEL_SHARED_URL=redis://localhost:6379/3
126
+ CHANNEL__DEFAULT__BACKEND=memory
127
+ CHANNEL__SHARED__BACKEND=redis
128
+ CHANNEL__SHARED__URL=redis://localhost:6379/3
129
129
  """
130
130
 
131
131
  backend: str = Field(
@@ -141,10 +141,10 @@ class ChannelInstanceConfig(MultiInstanceSettings):
141
141
  class MQInstanceConfig(MultiInstanceSettings):
142
142
  """消息队列实例配置。
143
143
 
144
- 环境变量格式: MQ_{INSTANCE}_{FIELD}
144
+ 环境变量格式: MQ__{INSTANCE}__{FIELD}
145
145
  示例:
146
- MQ_DEFAULT_BACKEND=redis
147
- MQ_DEFAULT_URL=redis://localhost:6379/4
146
+ MQ__DEFAULT__BACKEND=redis
147
+ MQ__DEFAULT__URL=redis://localhost:6379/4
148
148
  """
149
149
 
150
150
  backend: str = Field(
@@ -160,11 +160,11 @@ class MQInstanceConfig(MultiInstanceSettings):
160
160
  class EventInstanceConfig(MultiInstanceSettings):
161
161
  """事件总线实例配置。
162
162
 
163
- 环境变量格式: EVENT_{INSTANCE}_{FIELD}
163
+ 环境变量格式: EVENT__{INSTANCE}__{FIELD}
164
164
  示例:
165
- EVENT_DEFAULT_BACKEND=memory
166
- EVENT_DISTRIBUTED_BACKEND=redis
167
- EVENT_DISTRIBUTED_URL=redis://localhost:6379/5
165
+ EVENT__DEFAULT__BACKEND=memory
166
+ EVENT__DISTRIBUTED__BACKEND=redis
167
+ EVENT__DISTRIBUTED__URL=redis://localhost:6379/5
168
168
  """
169
169
 
170
170
  backend: str = Field(
@@ -182,10 +182,12 @@ class EventInstanceConfig(MultiInstanceSettings):
182
182
  # =============================================================================
183
183
 
184
184
 
185
- class DatabaseSettings(BaseSettings):
185
+ class DatabaseSettings(BaseModel):
186
186
  """数据库配置(单实例)。
187
187
 
188
- 推荐使用多实例配置: DATABASE_{INSTANCE}_{FIELD}
188
+ 环境变量格式: DATABASE__{FIELD}
189
+ 示例: DATABASE__URL, DATABASE__POOL_SIZE
190
+ 多实例格式: DATABASE__{INSTANCE}__{FIELD}
189
191
  """
190
192
 
191
193
  url: str = Field(
@@ -216,23 +218,18 @@ class DatabaseSettings(BaseSettings):
216
218
  default=True,
217
219
  description="是否在获取连接前进行 PING"
218
220
  )
219
-
220
- model_config = SettingsConfigDict(
221
- env_prefix="DATABASE_",
222
- case_sensitive=False,
223
- )
224
221
 
225
222
 
226
- class CacheSettings(BaseSettings):
223
+ class CacheSettings(BaseModel):
227
224
  """缓存配置。
228
225
 
229
- 环境变量前缀: CACHE_
230
- 示例: CACHE_TYPE, CACHE_URL, CACHE_MAX_SIZE
226
+ 环境变量格式: CACHE__{FIELD}
227
+ 示例: CACHE__TYPE, CACHE__URL, CACHE__MAX_SIZE
231
228
 
232
229
  支持的缓存类型:
233
230
  - memory: 内存缓存(默认,无需 URL)
234
- - redis: Redis 缓存(需要设置 CACHE_URL
235
- - memcached: Memcached 缓存(需要设置 CACHE_URL
231
+ - redis: Redis 缓存(需要设置 CACHE__URL
232
+ - memcached: Memcached 缓存(需要设置 CACHE__URL
236
233
  """
237
234
 
238
235
  cache_type: str = Field(
@@ -247,22 +244,14 @@ class CacheSettings(BaseSettings):
247
244
  default=1000,
248
245
  description="内存缓存最大大小"
249
246
  )
250
-
251
- model_config = SettingsConfigDict(
252
- env_prefix="CACHE_",
253
- case_sensitive=False,
254
- )
255
247
 
256
248
 
257
- class StorageSettings(BaseSettings):
249
+ class StorageSettings(BaseModel):
258
250
  """对象存储组件接入配置(Application 层)。
259
251
 
260
- 说明:
261
- - Application 层负责从 env/.env 读取配置(快速接入组件)
262
- - Infrastructure 层的 storage 仅接受 Pydantic(BaseModel) 的配置对象,不读取 env
263
-
264
- 环境变量前缀:STORAGE_
265
- """
252
+ 环境变量格式: STORAGE__{FIELD}
253
+ 示例: STORAGE__TYPE, STORAGE__BUCKET_NAME
254
+ """
266
255
 
267
256
  enabled: bool = Field(default=True, description="是否启用存储组件")
268
257
 
@@ -289,22 +278,16 @@ class StorageSettings(BaseSettings):
289
278
  # local
290
279
  base_path: str = Field(default="./storage", description="本地存储基础目录")
291
280
 
292
- model_config = SettingsConfigDict(
293
- env_prefix="STORAGE_",
294
- case_sensitive=False,
295
- extra="ignore",
296
- )
297
281
 
298
-
299
- class ServerSettings(BaseSettings):
282
+ class ServerSettings(BaseModel):
300
283
  """服务器配置。
301
284
 
302
- 环境变量前缀: SERVER_
303
- 示例: SERVER_HOST, SERVER_PORT, SERVER_RELOAD
285
+ 环境变量格式: SERVER__{FIELD}
286
+ 示例: SERVER__HOST, SERVER__PORT, SERVER__RELOAD
304
287
  """
305
288
 
306
289
  host: str = Field(
307
- default="127.0.0.1",
290
+ default="0.0.0.0",
308
291
  description="服务器监听地址"
309
292
  )
310
293
  port: int = Field(
@@ -319,18 +302,13 @@ class ServerSettings(BaseSettings):
319
302
  default=1,
320
303
  description="工作进程数"
321
304
  )
322
-
323
- model_config = SettingsConfigDict(
324
- env_prefix="SERVER_",
325
- case_sensitive=False,
326
- )
327
305
 
328
306
 
329
- class CORSSettings(BaseSettings):
307
+ class CORSSettings(BaseModel):
330
308
  """CORS配置。
331
309
 
332
- 环境变量前缀: CORS_
333
- 示例: CORS_ORIGINS, CORS_ALLOW_CREDENTIALS, CORS_ALLOW_METHODS
310
+ 环境变量格式: CORS__{FIELD}
311
+ 示例: CORS__ORIGINS, CORS__ALLOW_CREDENTIALS, CORS__ALLOW_METHODS
334
312
  """
335
313
 
336
314
  origins: list[str] = Field(
@@ -349,18 +327,13 @@ class CORSSettings(BaseSettings):
349
327
  default=["*"],
350
328
  description="允许的CORS头"
351
329
  )
352
-
353
- model_config = SettingsConfigDict(
354
- env_prefix="CORS_",
355
- case_sensitive=False,
356
- )
357
330
 
358
331
 
359
- class LogSettings(BaseSettings):
332
+ class LogSettings(BaseModel):
360
333
  """日志配置。
361
334
 
362
- 环境变量前缀: LOG_
363
- 示例: LOG_LEVEL, LOG_DIR, LOG_ROTATION_TIME, LOG_RETENTION_DAYS
335
+ 环境变量格式: LOG__{FIELD}
336
+ 示例: LOG__LEVEL, LOG__DIR, LOG__ROTATION_TIME, LOG__RETENTION_DAYS
364
337
  """
365
338
 
366
339
  level: str = Field(
@@ -399,24 +372,19 @@ class LogSettings(BaseSettings):
399
372
  default=False,
400
373
  description="是否记录 WebSocket 消息内容(注意性能和敏感数据)"
401
374
  )
402
-
403
- model_config = SettingsConfigDict(
404
- env_prefix="LOG_",
405
- case_sensitive=False,
406
- )
407
375
 
408
376
 
409
- class ServiceSettings(BaseSettings):
377
+ class ServiceSettings(BaseModel):
410
378
  """服务配置。
411
379
 
412
- 环境变量前缀: SERVICE_
413
- 示例: SERVICE_NAME, SERVICE_TYPE
380
+ 环境变量格式: SERVICE__{FIELD}
381
+ 示例: SERVICE__NAME, SERVICE__TYPE
414
382
 
415
383
  服务类型说明:
416
- - api: 运行 API 服务(SCHEDULER_ENABLED 决定是否同时运行调度器)
384
+ - api: 运行 API 服务(SCHEDULER__ENABLED 决定是否同时运行调度器)
417
385
  - worker: 运行任务队列 Worker(处理异步任务)
418
386
 
419
- 独立调度器通过 `aury scheduler` 命令运行,不需要配置 SERVICE_TYPE
387
+ 独立调度器通过 `aury scheduler` 命令运行,不需要配置 SERVICE__TYPE
420
388
  """
421
389
 
422
390
  name: str = Field(
@@ -428,21 +396,16 @@ class ServiceSettings(BaseSettings):
428
396
  description="服务类型(api/worker)"
429
397
  )
430
398
 
431
- model_config = SettingsConfigDict(
432
- env_prefix="SERVICE_",
433
- case_sensitive=False,
434
- )
435
399
 
436
-
437
- class SchedulerSettings(BaseSettings):
400
+ class SchedulerSettings(BaseModel):
438
401
  """调度器配置。
439
402
 
440
- 环境变量前缀: SCHEDULER_
441
- 示例: SCHEDULER_ENABLED, SCHEDULER_SCHEDULE_MODULES
403
+ 环境变量格式: SCHEDULER__{FIELD}
404
+ 示例: SCHEDULER__ENABLED, SCHEDULER__SCHEDULE_MODULES
442
405
 
443
- 仅在 SERVICE_TYPE=api 时有效:
444
- - SCHEDULER_ENABLED=true: API 服务同时运行内嵌调度器(默认)
445
- - SCHEDULER_ENABLED=false: 只运行 API,不启动调度器
406
+ 仅在 SERVICE__TYPE=api 时有效:
407
+ - SCHEDULER__ENABLED=true: API 服务同时运行内嵌调度器(默认)
408
+ - SCHEDULER__ENABLED=false: 只运行 API,不启动调度器
446
409
 
447
410
  独立调度器通过 `aury scheduler` 命令运行,不需要此配置。
448
411
  """
@@ -455,18 +418,13 @@ class SchedulerSettings(BaseSettings):
455
418
  default_factory=list,
456
419
  description="定时任务模块列表。为空时自动发现 schedules 模块"
457
420
  )
458
-
459
- model_config = SettingsConfigDict(
460
- env_prefix="SCHEDULER_",
461
- case_sensitive=False,
462
- )
463
421
 
464
422
 
465
- class TaskSettings(BaseSettings):
423
+ class TaskSettings(BaseModel):
466
424
  """任务队列配置。
467
425
 
468
- 环境变量前缀: TASK_
469
- 示例: TASK_BROKER_URL, TASK_MAX_RETRIES
426
+ 环境变量格式: TASK__{FIELD}
427
+ 示例: TASK__BROKER_URL, TASK__MAX_RETRIES
470
428
  """
471
429
 
472
430
  broker_url: str | None = Field(
@@ -481,18 +439,13 @@ class TaskSettings(BaseSettings):
481
439
  default=3600,
482
440
  description="任务超时时间(秒)"
483
441
  )
484
-
485
- model_config = SettingsConfigDict(
486
- env_prefix="TASK_",
487
- case_sensitive=False,
488
- )
489
442
 
490
443
 
491
- class EventSettings(BaseSettings):
444
+ class EventSettings(BaseModel):
492
445
  """事件总线配置。
493
446
 
494
- 环境变量前缀: EVENT_
495
- 示例: EVENT_BROKER_URL, EVENT_EXCHANGE_NAME
447
+ 环境变量格式: EVENT__{FIELD}
448
+ 示例: EVENT__BROKER_URL, EVENT__EXCHANGE_NAME
496
449
  """
497
450
 
498
451
  broker_url: str | None = Field(
@@ -503,18 +456,13 @@ class EventSettings(BaseSettings):
503
456
  default="aury.events",
504
457
  description="事件交换机名称"
505
458
  )
506
-
507
- model_config = SettingsConfigDict(
508
- env_prefix="EVENT_",
509
- case_sensitive=False,
510
- )
511
459
 
512
460
 
513
- class MessageQueueSettings(BaseSettings):
461
+ class MessageQueueSettings(BaseModel):
514
462
  """消息队列配置。
515
463
 
516
- 环境变量前缀: MQ_
517
- 示例: MQ_BROKER_URL, MQ_DEFAULT_QUEUE, MQ_SERIALIZER
464
+ 环境变量格式: MQ__{FIELD}
465
+ 示例: MQ__BROKER_URL, MQ__DEFAULT_QUEUE, MQ__SERIALIZER
518
466
 
519
467
  与 Task(任务队列)的区别:
520
468
  - Task: 基于 Dramatiq,用于异步任务处理(API + Worker 模式)
@@ -546,18 +494,13 @@ class MessageQueueSettings(BaseSettings):
546
494
  default=1,
547
495
  description="预取消息数量"
548
496
  )
549
-
550
- model_config = SettingsConfigDict(
551
- env_prefix="MQ_",
552
- case_sensitive=False,
553
- )
554
497
 
555
498
 
556
- class MigrationSettings(BaseSettings):
499
+ class MigrationSettings(BaseModel):
557
500
  """数据库迁移配置。
558
501
 
559
- 环境变量前缀: MIGRATION_
560
- 示例: MIGRATION_CONFIG_PATH, MIGRATION_SCRIPT_LOCATION, MIGRATION_MODEL_MODULES
502
+ 环境变量格式: MIGRATION__{FIELD}
503
+ 示例: MIGRATION__CONFIG_PATH, MIGRATION__SCRIPT_LOCATION, MIGRATION__MODEL_MODULES
561
504
  """
562
505
 
563
506
  config_path: str = Field(
@@ -580,20 +523,15 @@ class MigrationSettings(BaseSettings):
580
523
  default=True,
581
524
  description="是否自动创建迁移配置和目录"
582
525
  )
583
-
584
- model_config = SettingsConfigDict(
585
- env_prefix="MIGRATION_",
586
- case_sensitive=False,
587
- )
588
526
 
589
527
 
590
- class RPCClientSettings(BaseSettings):
528
+ class RPCClientSettings(BaseModel):
591
529
  """RPC 客户端调用配置。
592
530
 
593
531
  用于配置客户端调用其他服务时的行为。
594
532
 
595
- 环境变量前缀: RPC_CLIENT_
596
- 示例: 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
597
535
  """
598
536
 
599
537
  services: dict[str, str] = Field(
@@ -620,20 +558,15 @@ class RPCClientSettings(BaseSettings):
620
558
  default=True,
621
559
  description="是否在配置中找不到时使用 DNS 解析(K8s/Docker Compose 自动 DNS)"
622
560
  )
623
-
624
- model_config = SettingsConfigDict(
625
- env_prefix="RPC_CLIENT_",
626
- case_sensitive=False,
627
- )
628
561
 
629
562
 
630
- class RPCServiceSettings(BaseSettings):
563
+ class RPCServiceSettings(BaseModel):
631
564
  """RPC 服务注册配置。
632
565
 
633
566
  用于配置当前服务注册到服务注册中心时的信息。
634
567
 
635
- 环境变量前缀: RPC_SERVICE_
636
- 示例: 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
637
570
  """
638
571
 
639
572
  name: str | None = Field(
@@ -656,21 +589,16 @@ class RPCServiceSettings(BaseSettings):
656
589
  default=None,
657
590
  description="服务注册中心地址(如果使用外部注册中心)"
658
591
  )
659
-
660
- model_config = SettingsConfigDict(
661
- env_prefix="RPC_SERVICE_",
662
- case_sensitive=False,
663
- )
664
592
 
665
593
 
666
- class HealthCheckSettings(BaseSettings):
594
+ class HealthCheckSettings(BaseModel):
667
595
  """健康检查配置。
668
596
 
669
597
  用于配置 Aury 框架的默认健康检查端点。
670
598
  注意:此配置仅用于框架内置的健康检查端点,不影响服务自身的健康检查端点。
671
599
 
672
- 环境变量前缀: HEALTH_CHECK_
673
- 示例: HEALTH_CHECK_PATH, HEALTH_CHECK_ENABLED
600
+ 环境变量格式: HEALTH_CHECK__{FIELD}
601
+ 示例: HEALTH_CHECK__PATH, HEALTH_CHECK__ENABLED
674
602
  """
675
603
 
676
604
  path: str = Field(
@@ -681,22 +609,17 @@ class HealthCheckSettings(BaseSettings):
681
609
  default=True,
682
610
  description="是否启用 Aury 默认健康检查端点"
683
611
  )
684
-
685
- model_config = SettingsConfigDict(
686
- env_prefix="HEALTH_CHECK_",
687
- case_sensitive=False,
688
- )
689
612
 
690
613
 
691
- class AdminAuthSettings(BaseSettings):
614
+ class AdminAuthSettings(BaseModel):
692
615
  """管理后台认证配置。
693
616
 
694
- 环境变量前缀: ADMIN_AUTH_
695
- 示例: 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
696
619
 
697
620
  说明:
698
621
  - 内置模式仅保证 basic / bearer 开箱即用
699
- - jwt/custom 推荐由用户自定义 backend 实现(见 ADMIN_AUTH_BACKEND)
622
+ - jwt/custom 推荐由用户自定义 backend 实现
700
623
  """
701
624
 
702
625
  mode: Literal["none", "basic", "bearer", "jwt", "custom"] = Field(
@@ -723,17 +646,13 @@ class AdminAuthSettings(BaseSettings):
723
646
  description='自定义认证后端导入路径,如 "yourpkg.admin_auth:backend"',
724
647
  )
725
648
 
726
- model_config = SettingsConfigDict(
727
- env_prefix="ADMIN_AUTH_",
728
- case_sensitive=False,
729
- )
730
-
731
649
 
732
- class AdminConsoleSettings(BaseSettings):
650
+ class AdminConsoleSettings(BaseModel):
733
651
  """SQLAdmin 管理后台配置。
734
652
 
735
- 环境变量前缀: ADMIN_
736
- 示例: ADMIN_ENABLED, ADMIN_PATH, ADMIN_DATABASE_URL
653
+ 环境变量格式: ADMIN__{FIELD}
654
+ 示例: ADMIN__ENABLED, ADMIN__PATH, ADMIN__DATABASE_URL
655
+ 嵌套配置: ADMIN__AUTH__{FIELD}
737
656
  """
738
657
 
739
658
  enabled: bool = Field(default=False, description="是否启用管理后台")
@@ -757,11 +676,6 @@ class AdminConsoleSettings(BaseSettings):
757
676
 
758
677
  auth: AdminAuthSettings = Field(default_factory=AdminAuthSettings, description="管理后台认证配置")
759
678
 
760
- model_config = SettingsConfigDict(
761
- env_prefix="ADMIN_",
762
- case_sensitive=False,
763
- )
764
-
765
679
 
766
680
  class BaseConfig(BaseSettings):
767
681
  """基础配置类。
@@ -769,17 +683,22 @@ class BaseConfig(BaseSettings):
769
683
  所有应用配置的基类,提供通用配置项。
770
684
  初始化时自动从 .env 文件加载环境变量,然后由 pydantic-settings 读取环境变量。
771
685
 
772
- 多实例配置:
773
- 框架支持多种组件的多实例配置,使用统一的环境变量格式:
774
- {PREFIX}_{INSTANCE}_{FIELD}=value
686
+ 环境变量格式:
687
+ 使用双下划线 (__) 作为层级分隔符:
688
+ {SECTION}__{FIELD}=value
689
+ {SECTION}__{NESTED}__{FIELD}=value
775
690
 
776
- 示例:
777
- DATABASE_DEFAULT_URL=postgresql://main...
778
- DATABASE_ANALYTICS_URL=postgresql://analytics...
779
- CACHE_DEFAULT_BACKEND=redis
780
- CACHE_DEFAULT_URL=redis://localhost:6379/1
781
- MQ_DEFAULT_URL=redis://localhost:6379/2
782
- EVENT_DEFAULT_BACKEND=memory
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
783
702
 
784
703
  注意:Application 层配置完全独立,不依赖 Infrastructure 层。
785
704
  """
@@ -848,6 +767,7 @@ class BaseConfig(BaseSettings):
848
767
  model_config = SettingsConfigDict(
849
768
  case_sensitive=False,
850
769
  extra="ignore",
770
+ env_nested_delimiter="__",
851
771
  )
852
772
 
853
773
  # ========== 多实例配置访问方法 ==========
@@ -855,7 +775,7 @@ class BaseConfig(BaseSettings):
855
775
  def get_databases(self) -> dict[str, DatabaseInstanceConfig]:
856
776
  """获取所有数据库实例配置。
857
777
 
858
- 从环境变量解析 DATABASE_{INSTANCE}_{FIELD} 格式的配置。
778
+ 从环境变量解析 DATABASE__{INSTANCE}__{FIELD} 格式的配置。
859
779
  如果没有配置多实例,返回从单实例配置转换的 default 实例。
860
780
  """
861
781
  if self._databases is None:
@@ -878,7 +798,7 @@ class BaseConfig(BaseSettings):
878
798
  def get_caches(self) -> dict[str, CacheInstanceConfig]:
879
799
  """获取所有缓存实例配置。
880
800
 
881
- 从环境变量解析 CACHE_{INSTANCE}_{FIELD} 格式的配置。
801
+ 从环境变量解析 CACHE__{INSTANCE}__{FIELD} 格式的配置。
882
802
  如果没有配置多实例,返回从单实例配置转换的 default 实例。
883
803
  """
884
804
  if self._caches is None:
@@ -897,7 +817,7 @@ class BaseConfig(BaseSettings):
897
817
  def get_storages(self) -> dict[str, StorageInstanceConfig]:
898
818
  """获取所有存储实例配置。
899
819
 
900
- 从环境变量解析 STORAGE_{INSTANCE}_{FIELD} 格式的配置。
820
+ 从环境变量解析 STORAGE__{INSTANCE}__{FIELD} 格式的配置。
901
821
  如果没有配置多实例,返回从单实例配置转换的 default 实例。
902
822
  """
903
823
  if self._storages is None:
@@ -920,7 +840,7 @@ class BaseConfig(BaseSettings):
920
840
  def get_channels(self) -> dict[str, ChannelInstanceConfig]:
921
841
  """获取所有通道实例配置。
922
842
 
923
- 从环境变量解析 CHANNEL_{INSTANCE}_{FIELD} 格式的配置。
843
+ 从环境变量解析 CHANNEL__{INSTANCE}__{FIELD} 格式的配置。
924
844
  """
925
845
  if self._channels is None:
926
846
  loader = MultiInstanceConfigLoader("CHANNEL", ChannelInstanceConfig)
@@ -930,7 +850,7 @@ class BaseConfig(BaseSettings):
930
850
  def get_mqs(self) -> dict[str, MQInstanceConfig]:
931
851
  """获取所有消息队列实例配置。
932
852
 
933
- 从环境变量解析 MQ_{INSTANCE}_{FIELD} 格式的配置。
853
+ 从环境变量解析 MQ__{INSTANCE}__{FIELD} 格式的配置。
934
854
  """
935
855
  if self._mqs is None:
936
856
  loader = MultiInstanceConfigLoader("MQ", MQInstanceConfig)
@@ -940,7 +860,7 @@ class BaseConfig(BaseSettings):
940
860
  def get_events(self) -> dict[str, EventInstanceConfig]:
941
861
  """获取所有事件总线实例配置。
942
862
 
943
- 从环境变量解析 EVENT_{INSTANCE}_{FIELD} 格式的配置。
863
+ 从环境变量解析 EVENT__{INSTANCE}__{FIELD} 格式的配置。
944
864
  如果没有配置多实例,返回从单实例配置转换的 default 实例。
945
865
  """
946
866
  if self._events is None:
@@ -17,7 +17,7 @@ from starlette.requests import Request
17
17
  from starlette.responses import Response
18
18
 
19
19
  from aury.boot.application.errors import global_exception_handler
20
- from aury.boot.common.logging import logger, set_trace_id
20
+ from aury.boot.common.logging import get_request_contexts, logger, set_trace_id
21
21
 
22
22
 
23
23
  def log_request[T](func: Callable[..., T]) -> Callable[..., T]:
@@ -187,6 +187,12 @@ class RequestLoggingMiddleware(BaseHTTPMiddleware):
187
187
  )
188
188
  logger.log(log_level.upper(), response_log)
189
189
 
190
+ # 记录请求上下文(user_id, tenant_id 等用户注册的字段)
191
+ request_contexts = get_request_contexts()
192
+ if request_contexts:
193
+ ctx_str = " | ".join(f"{k}: {v}" for k, v in request_contexts.items())
194
+ logger.info(f"[REQUEST_CONTEXT] Trace-ID: {trace_id} | {ctx_str}")
195
+
190
196
  # 写入 access 日志(简洁格式)
191
197
  logger.bind(access=True).info(
192
198
  f"{request.method} {request.url.path} {status_code} {duration:.3f}s"
@@ -209,6 +215,13 @@ class RequestLoggingMiddleware(BaseHTTPMiddleware):
209
215
  f"请求处理失败: {request.method} {request.url.path} | "
210
216
  f"耗时: {duration:.3f}s | Trace-ID: {trace_id}"
211
217
  )
218
+
219
+ # 记录请求上下文(即使异常也要记录,便于追踪问题)
220
+ request_contexts = get_request_contexts()
221
+ if request_contexts:
222
+ ctx_str = " | ".join(f"{k}: {v}" for k, v in request_contexts.items())
223
+ logger.info(f"[REQUEST_CONTEXT] Trace-ID: {trace_id} | {ctx_str}")
224
+
212
225
  # 使用全局异常处理器生成响应,而不是直接抛出异常
213
226
  # BaseHTTPMiddleware 中直接 raise 会绕过 FastAPI 的异常处理器
214
227
  response = await global_exception_handler(request, exc)