aury-boot 0.0.30__tar.gz → 0.0.32__tar.gz
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.
- {aury_boot-0.0.30 → aury_boot-0.0.32}/PKG-INFO +4 -1
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/_version.py +2 -2
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/__init__.py +2 -4
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/app/components.py +2 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/config/settings.py +6 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/AGENTS.md.tpl +54 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/env_templates/messaging.tpl +21 -13
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/env_templates/monitoring.tpl +2 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/__init__.py +4 -8
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/channel/__init__.py +9 -8
- aury_boot-0.0.32/aury/boot/infrastructure/channel/backends/__init__.py +5 -0
- aury_boot-0.0.32/aury/boot/infrastructure/channel/backends/broadcaster.py +141 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/channel/base.py +5 -2
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/channel/manager.py +25 -24
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/events/__init__.py +4 -6
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/events/backends/__init__.py +2 -4
- aury_boot-0.0.32/aury/boot/infrastructure/events/backends/broadcaster.py +189 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/events/base.py +9 -4
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/events/manager.py +24 -20
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/alerting/manager.py +2 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/alerting/rules.py +16 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/tracing/processor.py +31 -1
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/tracing/provider.py +2 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/pyproject.toml +4 -0
- aury_boot-0.0.30/aury/boot/infrastructure/channel/backends/__init__.py +0 -9
- aury_boot-0.0.30/aury/boot/infrastructure/channel/backends/memory.py +0 -126
- aury_boot-0.0.30/aury/boot/infrastructure/channel/backends/redis.py +0 -130
- aury_boot-0.0.30/aury/boot/infrastructure/events/backends/memory.py +0 -86
- aury_boot-0.0.30/aury/boot/infrastructure/events/backends/redis.py +0 -169
- {aury_boot-0.0.30 → aury_boot-0.0.32}/.gitignore +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/README.md +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/adapter/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/adapter/base.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/adapter/config.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/adapter/decorators.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/adapter/exceptions.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/adapter/http.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/app/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/app/base.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/app/middlewares.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/app/startup.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/config/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/config/multi_instance.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/constants/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/constants/components.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/constants/scheduler.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/constants/service.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/errors/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/errors/chain.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/errors/codes.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/errors/exceptions.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/errors/handlers.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/errors/response.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/interfaces/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/interfaces/egress.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/interfaces/ingress.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/middleware/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/middleware/logging.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/migrations/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/migrations/manager.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/migrations/setup.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/rpc/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/rpc/base.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/rpc/client.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/rpc/discovery.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/scheduler/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/scheduler/runner.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/application/server/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/add.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/app.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/config.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/docker.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/docs.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/generate.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/init.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/migrate/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/migrate/app.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/migrate/commands.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/pkg.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/scheduler.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/server/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/server/app.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/generate/api.py.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/generate/model.py.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/generate/repository.py.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/generate/schema.py.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/generate/service.py.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/README.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/admin_console_init.py.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/alert_rules.example.yaml.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/00-overview.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/01-model.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/02-repository.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/03-service.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/04-schema.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/05-api.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/06-exception.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/07-cache.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/08-scheduler.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/09-tasks.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/10-storage.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/11-logging.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/12-admin.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/13-channel.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/14-mq.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/15-events.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/16-adapter.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/17-alerting.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/aury_docs/99-cli.md.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/config.py.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/conftest.py.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/env_templates/_header.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/env_templates/admin.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/env_templates/cache.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/env_templates/database.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/env_templates/log.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/env_templates/rpc.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/env_templates/scheduler.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/env_templates/service.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/env_templates/storage.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/env_templates/third_party.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/gitignore.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/main.py.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/modules/api.py.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/modules/exceptions.py.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/modules/schedules.py.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/templates/project/modules/tasks.py.tpl +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/commands/worker.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/common/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/common/exceptions/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/common/i18n/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/common/i18n/translator.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/common/logging/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/common/logging/context.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/common/logging/decorators.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/common/logging/format.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/common/logging/setup.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/contrib/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/contrib/admin_console/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/contrib/admin_console/auth.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/contrib/admin_console/discovery.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/contrib/admin_console/install.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/contrib/admin_console/utils.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/domain/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/domain/exceptions/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/domain/models/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/domain/models/base.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/domain/models/mixins.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/domain/models/models.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/domain/pagination/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/domain/repository/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/domain/repository/impl.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/domain/repository/interceptors.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/domain/repository/interface.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/domain/repository/query_builder.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/domain/service/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/domain/service/base.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/domain/transaction/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/cache/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/cache/backends.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/cache/base.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/cache/exceptions.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/cache/factory.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/cache/manager.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/clients/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/clients/rabbitmq/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/clients/rabbitmq/config.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/clients/rabbitmq/manager.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/clients/redis/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/clients/redis/config.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/clients/redis/manager.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/database/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/database/config.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/database/exceptions.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/database/manager.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/database/query_tools/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/database/strategies/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/di/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/di/container.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/events/backends/rabbitmq.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/events/middleware.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/alerting/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/alerting/aggregator.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/alerting/events.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/alerting/notifiers/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/alerting/notifiers/base.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/alerting/notifiers/feishu.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/alerting/notifiers/webhook.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/health/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/tracing/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/tracing/context.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/tracing/logging.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/monitoring/tracing/tracing.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/mq/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/mq/backends/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/mq/backends/rabbitmq.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/mq/backends/redis.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/mq/base.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/mq/manager.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/scheduler/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/scheduler/exceptions.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/scheduler/manager.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/storage/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/storage/base.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/storage/exceptions.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/storage/factory.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/tasks/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/tasks/config.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/tasks/constants.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/tasks/exceptions.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/infrastructure/tasks/manager.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/testing/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/testing/base.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/testing/client.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/testing/factory.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/toolkit/__init__.py +0 -0
- {aury_boot-0.0.30 → aury_boot-0.0.32}/aury/boot/toolkit/http/__init__.py +0 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aury-boot
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.32
|
|
4
4
|
Summary: Aury Boot - 基于 FastAPI 生态的企业级 API 开发框架
|
|
5
5
|
Requires-Python: >=3.13
|
|
6
6
|
Requires-Dist: alembic>=1.17.2
|
|
7
7
|
Requires-Dist: aury-sdk-storage[aws]>=0.0.6
|
|
8
8
|
Requires-Dist: babel>=2.17.0
|
|
9
|
+
Requires-Dist: broadcaster[redis]>=0.3.1
|
|
9
10
|
Requires-Dist: faker>=38.2.0
|
|
10
11
|
Requires-Dist: fastapi>=0.122.0
|
|
11
12
|
Requires-Dist: greenlet>=3.2.4
|
|
@@ -30,6 +31,8 @@ Requires-Dist: aury-sdk-storage[aws]>=0.0.1; extra == 'all'
|
|
|
30
31
|
Requires-Dist: dramatiq>=1.18.0; extra == 'all'
|
|
31
32
|
Requires-Dist: pika>=1.3.2; extra == 'all'
|
|
32
33
|
Requires-Dist: redis>=7.1.0; extra == 'all'
|
|
34
|
+
Provides-Extra: broadcaster
|
|
35
|
+
Requires-Dist: broadcaster[redis]>=0.3.1; extra == 'broadcaster'
|
|
33
36
|
Provides-Extra: dev
|
|
34
37
|
Requires-Dist: mypy>=1.19.0; extra == 'dev'
|
|
35
38
|
Requires-Dist: pytest-asyncio>=1.3.0; extra == 'dev'
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.0.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 0,
|
|
31
|
+
__version__ = version = '0.0.32'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 0, 32)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -24,6 +24,7 @@ from aury.boot.domain.transaction import (
|
|
|
24
24
|
# 依赖注入容器(从 infrastructure 导入)
|
|
25
25
|
from aury.boot.infrastructure.di import Container, Lifetime, Scope, ServiceDescriptor
|
|
26
26
|
from aury.boot.infrastructure.events import (
|
|
27
|
+
BroadcasterEventBus,
|
|
27
28
|
Event,
|
|
28
29
|
EventBackend,
|
|
29
30
|
EventBusManager,
|
|
@@ -31,9 +32,7 @@ from aury.boot.infrastructure.events import (
|
|
|
31
32
|
EventType,
|
|
32
33
|
IEventBus,
|
|
33
34
|
# 后端实现
|
|
34
|
-
MemoryEventBus,
|
|
35
35
|
RabbitMQEventBus,
|
|
36
|
-
RedisEventBus,
|
|
37
36
|
)
|
|
38
37
|
|
|
39
38
|
from . import interfaces, rpc
|
|
@@ -108,14 +107,13 @@ __all__ = [
|
|
|
108
107
|
"IEventBus",
|
|
109
108
|
"Lifetime",
|
|
110
109
|
"LogSettings",
|
|
111
|
-
"
|
|
110
|
+
"BroadcasterEventBus",
|
|
112
111
|
"Middleware",
|
|
113
112
|
"MiddlewareName",
|
|
114
113
|
"MigrationComponent",
|
|
115
114
|
# 迁移
|
|
116
115
|
"MigrationManager",
|
|
117
116
|
"RabbitMQEventBus",
|
|
118
|
-
"RedisEventBus",
|
|
119
117
|
"RequestLoggingMiddleware",
|
|
120
118
|
"SchedulerComponent",
|
|
121
119
|
"SchedulerMode",
|
|
@@ -628,6 +628,7 @@ class TelemetryPlugin(Plugin):
|
|
|
628
628
|
alert_on_slow_sql=config.alert.alert_on_slow_sql,
|
|
629
629
|
alert_on_error=config.alert.alert_on_error,
|
|
630
630
|
alert_callback=alert_callback,
|
|
631
|
+
slow_request_exclude_paths=config.alert.slow_request_exclude_paths,
|
|
631
632
|
traces_endpoint=config.telemetry.traces_endpoint,
|
|
632
633
|
traces_headers=config.telemetry.traces_headers,
|
|
633
634
|
logs_endpoint=config.telemetry.logs_endpoint,
|
|
@@ -753,6 +754,7 @@ class AlertComponent(Component):
|
|
|
753
754
|
"slow_sql_aggregate": config.alert.slow_sql_aggregate,
|
|
754
755
|
"exception_aggregate": config.alert.exception_aggregate,
|
|
755
756
|
"suppress_seconds": config.alert.suppress_seconds,
|
|
757
|
+
"slow_request_exclude_paths": config.alert.slow_request_exclude_paths,
|
|
756
758
|
},
|
|
757
759
|
notifiers=config.alert.get_notifiers(),
|
|
758
760
|
)
|
|
@@ -696,6 +696,12 @@ class AlertSettings(BaseModel):
|
|
|
696
696
|
description="是否对异常发送告警(默认只对 5xx 告警,4xx 业务异常不告警)"
|
|
697
697
|
)
|
|
698
698
|
|
|
699
|
+
# 慢请求路径排除配置
|
|
700
|
+
slow_request_exclude_paths: list[str] = Field(
|
|
701
|
+
default_factory=list,
|
|
702
|
+
description="排除慢请求告警的路径列表(支持 * 通配符),如 SSE/WebSocket 长连接接口"
|
|
703
|
+
)
|
|
704
|
+
|
|
699
705
|
# 默认累计触发配置
|
|
700
706
|
aggregate_window: int = Field(
|
|
701
707
|
default=10,
|
|
@@ -127,6 +127,60 @@ mypy {package_name}/
|
|
|
127
127
|
- **[aury_docs/99-cli.md](./aury_docs/99-cli.md)** - CLI 命令参考
|
|
128
128
|
- **[.env.example](./.env.example)** - 所有可用环境变量
|
|
129
129
|
|
|
130
|
+
## 配置结构
|
|
131
|
+
|
|
132
|
+
框架使用 `BaseConfig` 统一管理配置,环境变量通过 `__` 分隔符映射到嵌套配置:
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
# 配置结构(BaseConfig)
|
|
136
|
+
class BaseConfig(BaseSettings):
|
|
137
|
+
# 基础服务
|
|
138
|
+
server: ServerSettings # SERVER__*
|
|
139
|
+
cors: CORSSettings # CORS__*
|
|
140
|
+
log: LogSettings # LOG__*
|
|
141
|
+
health_check: HealthCheckSettings # HEALTH_CHECK__*
|
|
142
|
+
admin: AdminConsoleSettings # ADMIN__*
|
|
143
|
+
|
|
144
|
+
# 数据与缓存
|
|
145
|
+
database: DatabaseSettings # DATABASE__*
|
|
146
|
+
cache: CacheSettings # CACHE__*
|
|
147
|
+
channel: ChannelSettings # CHANNEL__*
|
|
148
|
+
storage: StorageSettings # STORAGE__*
|
|
149
|
+
migration: MigrationSettings # MIGRATION__*
|
|
150
|
+
|
|
151
|
+
# 服务编排
|
|
152
|
+
service: ServiceSettings # SERVICE__*
|
|
153
|
+
scheduler: SchedulerSettings # SCHEDULER__*
|
|
154
|
+
|
|
155
|
+
# 异步与事件
|
|
156
|
+
task: TaskSettings # TASK__*
|
|
157
|
+
event: EventSettings # EVENT__*
|
|
158
|
+
|
|
159
|
+
# 微服务通信
|
|
160
|
+
rpc_client: RPCClientSettings # RPC_CLIENT__*
|
|
161
|
+
rpc_service: RPCServiceSettings # RPC_SERVICE__*
|
|
162
|
+
|
|
163
|
+
# 监控告警
|
|
164
|
+
telemetry: TelemetrySettings # TELEMETRY__*
|
|
165
|
+
alert: AlertSettings # ALERT__*
|
|
166
|
+
|
|
167
|
+
model_config = SettingsConfigDict(
|
|
168
|
+
env_nested_delimiter="__", # 环境变量分隔符
|
|
169
|
+
)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**环境变量命名规则**:`{SECTION}__{FIELD}`
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# 示例
|
|
176
|
+
DATABASE__URL=postgresql://...
|
|
177
|
+
DATABASE__POOL_SIZE=10
|
|
178
|
+
CACHE__CACHE_TYPE=redis
|
|
179
|
+
CACHE__URL=redis://localhost:6379
|
|
180
|
+
ALERT__ENABLED=true
|
|
181
|
+
ALERT__SLOW_REQUEST_THRESHOLD=1.0
|
|
182
|
+
```
|
|
183
|
+
|
|
130
184
|
## 代码规范
|
|
131
185
|
|
|
132
186
|
> 项目所有业务配置请通过应用 `settings`/配置对象获取,**不要**直接使用 `os.environ` 在业务代码中读环境变量。
|
|
@@ -2,14 +2,18 @@
|
|
|
2
2
|
# =============================================================================
|
|
3
3
|
# 流式通道配置 (CHANNEL__) - SSE/实时通信
|
|
4
4
|
# =============================================================================
|
|
5
|
+
# 基于 Broadcaster 库,通过 URL scheme 切换后端
|
|
6
|
+
# 支持: memory:// | redis://host:port/db | kafka://host:port | postgres://...
|
|
7
|
+
#
|
|
5
8
|
# 单实例配置:
|
|
6
|
-
# CHANNEL__BACKEND=
|
|
7
|
-
#
|
|
8
|
-
# CHANNEL__URL=redis://localhost:6379/3
|
|
9
|
+
# CHANNEL__BACKEND=broadcaster
|
|
10
|
+
# CHANNEL__URL=memory://
|
|
11
|
+
# 分布式: CHANNEL__URL=redis://localhost:6379/3
|
|
9
12
|
#
|
|
10
13
|
# 多实例配置 (格式: CHANNEL__{{INSTANCE}}__{{FIELD}}):
|
|
11
|
-
# CHANNEL__SSE__BACKEND=
|
|
12
|
-
#
|
|
14
|
+
# CHANNEL__SSE__BACKEND=broadcaster
|
|
15
|
+
# CHANNEL__SSE__URL=memory://
|
|
16
|
+
# CHANNEL__NOTIFICATION__BACKEND=broadcaster
|
|
13
17
|
# CHANNEL__NOTIFICATION__URL=redis://localhost:6379/3
|
|
14
18
|
|
|
15
19
|
# =============================================================================
|
|
@@ -32,18 +36,22 @@
|
|
|
32
36
|
# =============================================================================
|
|
33
37
|
# 事件总线配置 (EVENT__)
|
|
34
38
|
# =============================================================================
|
|
39
|
+
# 基于 Broadcaster 库,通过 URL scheme 切换后端
|
|
40
|
+
# 支持: memory:// | redis://host:port/db | kafka://host:port | postgres://...
|
|
41
|
+
# RabbitMQ 需使用 backend=rabbitmq
|
|
42
|
+
#
|
|
35
43
|
# 单实例配置:
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
|
|
44
|
+
# EVENT__BACKEND=broadcaster
|
|
45
|
+
# EVENT__URL=memory://
|
|
46
|
+
# 分布式: EVENT__URL=redis://localhost:6379/5
|
|
47
|
+
#
|
|
39
48
|
# 多实例配置 (格式: EVENT__{{INSTANCE}}__{{FIELD}}):
|
|
40
|
-
# EVENT__DEFAULT__BACKEND=
|
|
41
|
-
#
|
|
49
|
+
# EVENT__DEFAULT__BACKEND=broadcaster
|
|
50
|
+
# EVENT__DEFAULT__URL=memory://
|
|
51
|
+
# EVENT__DISTRIBUTED__BACKEND=broadcaster
|
|
42
52
|
# EVENT__DISTRIBUTED__URL=redis://localhost:6379/5
|
|
43
|
-
# EVENT__DISTRIBUTED__KEY_PREFIX=events:
|
|
44
53
|
#
|
|
45
|
-
# RabbitMQ
|
|
54
|
+
# RabbitMQ 后端 (复杂消息场景):
|
|
46
55
|
# EVENT__DOMAIN__BACKEND=rabbitmq
|
|
47
56
|
# EVENT__DOMAIN__URL=amqp://guest:guest@localhost:5672/
|
|
48
57
|
# EVENT__DOMAIN__EXCHANGE_NAME=domain.events
|
|
49
|
-
# EVENT__DOMAIN__EXCHANGE_TYPE=topic
|
|
@@ -21,6 +21,8 @@ ALERT__SLOW_SQL_THRESHOLD=0.5
|
|
|
21
21
|
ALERT__ALERT_ON_SLOW_REQUEST=true
|
|
22
22
|
ALERT__ALERT_ON_SLOW_SQL=true
|
|
23
23
|
ALERT__ALERT_ON_ERROR=true
|
|
24
|
+
# 慢请求排除路径(SSE/WebSocket 等长连接接口,支持 * 通配符)
|
|
25
|
+
# ALERT__SLOW_REQUEST_EXCLUDE_PATHS=["*/subscribe", "*/ws", "*/stream"]
|
|
24
26
|
# 聚合与抑制
|
|
25
27
|
ALERT__AGGREGATE_WINDOW=10
|
|
26
28
|
ALERT__SLOW_REQUEST_AGGREGATE=5
|
|
@@ -27,12 +27,11 @@ from .cache import (
|
|
|
27
27
|
|
|
28
28
|
# 通道 (SSE/PubSub)
|
|
29
29
|
from .channel import (
|
|
30
|
+
BroadcasterChannel,
|
|
30
31
|
ChannelBackend,
|
|
31
32
|
ChannelManager,
|
|
32
33
|
ChannelMessage,
|
|
33
34
|
IChannel,
|
|
34
|
-
MemoryChannel,
|
|
35
|
-
RedisChannel,
|
|
36
35
|
)
|
|
37
36
|
|
|
38
37
|
# RabbitMQ 客户端
|
|
@@ -47,15 +46,14 @@ from .di import Container, Lifetime, Scope, ServiceDescriptor
|
|
|
47
46
|
|
|
48
47
|
# 事件总线
|
|
49
48
|
from .events import (
|
|
49
|
+
BroadcasterEventBus,
|
|
50
50
|
Event,
|
|
51
51
|
EventBackend,
|
|
52
52
|
EventBusManager,
|
|
53
53
|
EventHandler,
|
|
54
54
|
EventType,
|
|
55
55
|
IEventBus,
|
|
56
|
-
MemoryEventBus,
|
|
57
56
|
RabbitMQEventBus,
|
|
58
|
-
RedisEventBus,
|
|
59
57
|
)
|
|
60
58
|
|
|
61
59
|
# 消息队列
|
|
@@ -103,6 +101,7 @@ __all__ = [
|
|
|
103
101
|
"CacheFactory",
|
|
104
102
|
"CacheManager",
|
|
105
103
|
# 通道
|
|
104
|
+
"BroadcasterChannel",
|
|
106
105
|
"ChannelBackend",
|
|
107
106
|
"ChannelManager",
|
|
108
107
|
"ChannelMessage",
|
|
@@ -128,19 +127,16 @@ __all__ = [
|
|
|
128
127
|
"MQMessage",
|
|
129
128
|
"MemcachedCache",
|
|
130
129
|
"MemoryCache",
|
|
131
|
-
"MemoryChannel",
|
|
132
|
-
"MemoryEventBus",
|
|
133
130
|
"RabbitMQ",
|
|
134
131
|
# RabbitMQ 客户端
|
|
135
132
|
"RabbitMQClient",
|
|
136
133
|
"RabbitMQConfig",
|
|
137
134
|
"RabbitMQEventBus",
|
|
135
|
+
"BroadcasterEventBus",
|
|
138
136
|
"RedisCache",
|
|
139
|
-
"RedisChannel",
|
|
140
137
|
# Redis 客户端
|
|
141
138
|
"RedisClient",
|
|
142
139
|
"RedisConfig",
|
|
143
|
-
"RedisEventBus",
|
|
144
140
|
"RedisMQ",
|
|
145
141
|
"S3Storage",
|
|
146
142
|
# 调度器
|
|
@@ -2,23 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
提供发布/订阅模式的通道功能,用于 SSE、WebSocket 等实时通信场景。
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- memory
|
|
7
|
-
- redis
|
|
5
|
+
支持的后端(通过 Broadcaster 库):
|
|
6
|
+
- memory:// - 内存通道(单进程,开发/测试用)
|
|
7
|
+
- redis:// - Redis Pub/Sub(多进程/分布式)
|
|
8
|
+
- kafka:// - Apache Kafka
|
|
9
|
+
- postgres:// - PostgreSQL LISTEN/NOTIFY
|
|
8
10
|
"""
|
|
9
11
|
|
|
10
|
-
from .backends import
|
|
12
|
+
from .backends import BroadcasterChannel
|
|
11
13
|
from .base import ChannelBackend, ChannelMessage, IChannel
|
|
12
14
|
from .manager import ChannelManager
|
|
13
15
|
|
|
14
16
|
__all__ = [
|
|
15
17
|
# 接口和类型
|
|
16
18
|
"ChannelBackend",
|
|
17
|
-
# 管理器
|
|
18
|
-
"ChannelManager",
|
|
19
19
|
"ChannelMessage",
|
|
20
20
|
"IChannel",
|
|
21
|
+
# 管理器
|
|
22
|
+
"ChannelManager",
|
|
21
23
|
# 后端实现
|
|
22
|
-
"
|
|
23
|
-
"RedisChannel",
|
|
24
|
+
"BroadcasterChannel",
|
|
24
25
|
]
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""Broadcaster 通道后端。
|
|
2
|
+
|
|
3
|
+
基于 Broadcaster 库实现,支持多种后端:
|
|
4
|
+
- memory:// - 内存(单进程,开发/测试用)
|
|
5
|
+
- redis:// - Redis Pub/Sub(多进程/分布式)
|
|
6
|
+
- kafka:// - Apache Kafka
|
|
7
|
+
- postgres:// - PostgreSQL LISTEN/NOTIFY
|
|
8
|
+
|
|
9
|
+
优势:
|
|
10
|
+
- 共享连接池,支持成千上万并发订阅
|
|
11
|
+
- 自动重连机制
|
|
12
|
+
- 统一 API,通过 URL scheme 切换后端
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
from collections.abc import AsyncIterator
|
|
19
|
+
from datetime import datetime
|
|
20
|
+
|
|
21
|
+
from broadcaster import Broadcast
|
|
22
|
+
|
|
23
|
+
from aury.boot.common.logging import logger
|
|
24
|
+
|
|
25
|
+
from ..base import ChannelMessage, IChannel
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class BroadcasterChannel(IChannel):
|
|
29
|
+
"""Broadcaster 通道实现。
|
|
30
|
+
|
|
31
|
+
使用 Broadcaster 库统一处理多种后端,解决原生实现的连接池问题:
|
|
32
|
+
- 共享单个连接处理所有订阅
|
|
33
|
+
- 内部通过 asyncio.Queue 分发消息
|
|
34
|
+
- 支持成千上万并发订阅者
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, url: str) -> None:
|
|
38
|
+
"""初始化 Broadcaster 通道。
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
url: 连接 URL,支持的 scheme:
|
|
42
|
+
- memory:// - 内存后端
|
|
43
|
+
- redis://host:port/db - Redis Pub/Sub
|
|
44
|
+
- kafka://host:port - Apache Kafka
|
|
45
|
+
- postgres://user:pass@host:port/db - PostgreSQL
|
|
46
|
+
"""
|
|
47
|
+
self._url = url
|
|
48
|
+
self._broadcast = Broadcast(url)
|
|
49
|
+
self._connected = False
|
|
50
|
+
|
|
51
|
+
async def _ensure_connected(self) -> None:
|
|
52
|
+
"""确保已连接。"""
|
|
53
|
+
if not self._connected:
|
|
54
|
+
await self._broadcast.connect()
|
|
55
|
+
self._connected = True
|
|
56
|
+
logger.debug(f"Broadcaster 通道已连接: {self._mask_url(self._url)}")
|
|
57
|
+
|
|
58
|
+
def _mask_url(self, url: str) -> str:
|
|
59
|
+
"""URL 脱敏(隐藏密码)。"""
|
|
60
|
+
if "@" in url:
|
|
61
|
+
parts = url.split("@")
|
|
62
|
+
prefix = parts[0]
|
|
63
|
+
suffix = parts[1]
|
|
64
|
+
if ":" in prefix:
|
|
65
|
+
scheme_and_user = prefix.rsplit(":", 1)[0]
|
|
66
|
+
return f"{scheme_and_user}:***@{suffix}"
|
|
67
|
+
return url
|
|
68
|
+
|
|
69
|
+
async def publish(self, channel: str, message: ChannelMessage) -> None:
|
|
70
|
+
"""发布消息到通道。"""
|
|
71
|
+
await self._ensure_connected()
|
|
72
|
+
|
|
73
|
+
message.channel = channel
|
|
74
|
+
# 序列化消息
|
|
75
|
+
data = {
|
|
76
|
+
"data": message.data,
|
|
77
|
+
"event": message.event,
|
|
78
|
+
"id": message.id,
|
|
79
|
+
"channel": message.channel,
|
|
80
|
+
"timestamp": message.timestamp.isoformat(),
|
|
81
|
+
}
|
|
82
|
+
await self._broadcast.publish(channel=channel, message=json.dumps(data))
|
|
83
|
+
|
|
84
|
+
async def subscribe(self, channel: str) -> AsyncIterator[ChannelMessage]:
|
|
85
|
+
"""订阅通道。
|
|
86
|
+
|
|
87
|
+
Broadcaster 内部共享连接,每个订阅者不会创建新的连接。
|
|
88
|
+
"""
|
|
89
|
+
await self._ensure_connected()
|
|
90
|
+
|
|
91
|
+
async with self._broadcast.subscribe(channel=channel) as subscriber:
|
|
92
|
+
async for event in subscriber:
|
|
93
|
+
try:
|
|
94
|
+
data = json.loads(event.message)
|
|
95
|
+
message = ChannelMessage(
|
|
96
|
+
data=data.get("data"),
|
|
97
|
+
event=data.get("event"),
|
|
98
|
+
id=data.get("id"),
|
|
99
|
+
channel=data.get("channel") or channel,
|
|
100
|
+
timestamp=datetime.fromisoformat(data["timestamp"])
|
|
101
|
+
if data.get("timestamp")
|
|
102
|
+
else datetime.now(),
|
|
103
|
+
)
|
|
104
|
+
yield message
|
|
105
|
+
except (json.JSONDecodeError, KeyError, TypeError) as e:
|
|
106
|
+
logger.warning(f"解析通道消息失败: {e}")
|
|
107
|
+
|
|
108
|
+
async def psubscribe(self, pattern: str) -> AsyncIterator[ChannelMessage]:
|
|
109
|
+
"""模式订阅(通配符)。
|
|
110
|
+
|
|
111
|
+
注意:Broadcaster 目前不支持模式订阅,此方法会抛出 NotImplementedError。
|
|
112
|
+
如需模式订阅,请使用具体的 channel 名称。
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
pattern: 通道模式
|
|
116
|
+
|
|
117
|
+
Raises:
|
|
118
|
+
NotImplementedError: Broadcaster 不支持模式订阅
|
|
119
|
+
"""
|
|
120
|
+
raise NotImplementedError(
|
|
121
|
+
"Broadcaster 后端不支持模式订阅 (psubscribe)。"
|
|
122
|
+
"请使用具体的 channel 名称。"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
async def unsubscribe(self, channel: str) -> None:
|
|
126
|
+
"""取消订阅通道。
|
|
127
|
+
|
|
128
|
+
注意:Broadcaster 的订阅通过上下文管理器自动处理,
|
|
129
|
+
退出 subscribe() 的 async for 循环即可取消订阅。
|
|
130
|
+
"""
|
|
131
|
+
pass
|
|
132
|
+
|
|
133
|
+
async def close(self) -> None:
|
|
134
|
+
"""关闭通道。"""
|
|
135
|
+
if self._connected:
|
|
136
|
+
await self._broadcast.disconnect()
|
|
137
|
+
self._connected = False
|
|
138
|
+
logger.debug("Broadcaster 通道已关闭")
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
__all__ = ["BroadcasterChannel"]
|
|
@@ -16,8 +16,11 @@ from typing import Any
|
|
|
16
16
|
class ChannelBackend(Enum):
|
|
17
17
|
"""通道后端类型。"""
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
# Broadcaster 统一后端(支持 memory/redis/kafka/postgres,通过 URL scheme 区分)
|
|
20
|
+
BROADCASTER = "broadcaster"
|
|
21
|
+
# 未来扩展
|
|
22
|
+
RABBITMQ = "rabbitmq"
|
|
23
|
+
ROCKETMQ = "rocketmq"
|
|
21
24
|
|
|
22
25
|
|
|
23
26
|
@dataclass
|
|
@@ -9,8 +9,7 @@ from collections.abc import AsyncIterator
|
|
|
9
9
|
|
|
10
10
|
from aury.boot.common.logging import logger
|
|
11
11
|
|
|
12
|
-
from .backends.
|
|
13
|
-
from .backends.redis import RedisChannel
|
|
12
|
+
from .backends.broadcaster import BroadcasterChannel
|
|
14
13
|
from .base import ChannelBackend, ChannelMessage, IChannel
|
|
15
14
|
|
|
16
15
|
|
|
@@ -51,7 +50,6 @@ class ChannelManager:
|
|
|
51
50
|
self._backend: IChannel | None = None
|
|
52
51
|
self._backend_type: ChannelBackend | None = None
|
|
53
52
|
self._initialized: bool = False
|
|
54
|
-
self._redis_client = None
|
|
55
53
|
self._url: str | None = None
|
|
56
54
|
|
|
57
55
|
@classmethod
|
|
@@ -84,17 +82,19 @@ class ChannelManager:
|
|
|
84
82
|
|
|
85
83
|
async def initialize(
|
|
86
84
|
self,
|
|
87
|
-
backend: ChannelBackend | str = ChannelBackend.
|
|
85
|
+
backend: ChannelBackend | str = ChannelBackend.BROADCASTER,
|
|
88
86
|
*,
|
|
89
|
-
url: str
|
|
90
|
-
max_subscribers: int = 1000,
|
|
87
|
+
url: str = "memory://",
|
|
91
88
|
) -> ChannelManager:
|
|
92
89
|
"""初始化通道(链式调用)。
|
|
93
90
|
|
|
94
91
|
Args:
|
|
95
|
-
backend:
|
|
96
|
-
url:
|
|
97
|
-
|
|
92
|
+
backend: 后端类型,默认 broadcaster
|
|
93
|
+
url: 连接 URL,支持:
|
|
94
|
+
- memory:// - 内存后端(单进程,默认)
|
|
95
|
+
- redis://host:port/db - Redis Pub/Sub
|
|
96
|
+
- kafka://host:port - Apache Kafka
|
|
97
|
+
- postgres://user:pass@host/db - PostgreSQL
|
|
98
98
|
|
|
99
99
|
Returns:
|
|
100
100
|
self: 支持链式调用
|
|
@@ -110,24 +110,28 @@ class ChannelManager:
|
|
|
110
110
|
self._backend_type = backend
|
|
111
111
|
self._url = url
|
|
112
112
|
|
|
113
|
-
if backend == ChannelBackend.
|
|
114
|
-
self._backend =
|
|
115
|
-
elif backend
|
|
116
|
-
|
|
117
|
-
raise ValueError("Redis 通道需要提供 url 参数")
|
|
118
|
-
# 内部创建 RedisClient
|
|
119
|
-
from aury.boot.infrastructure.clients.redis import RedisClient
|
|
120
|
-
|
|
121
|
-
self._redis_client = RedisClient()
|
|
122
|
-
await self._redis_client.configure(url=url).initialize()
|
|
123
|
-
self._backend = RedisChannel(self._redis_client)
|
|
113
|
+
if backend == ChannelBackend.BROADCASTER:
|
|
114
|
+
self._backend = BroadcasterChannel(url)
|
|
115
|
+
elif backend in (ChannelBackend.RABBITMQ, ChannelBackend.ROCKETMQ):
|
|
116
|
+
raise NotImplementedError(f"{backend.value} 后端暂未实现")
|
|
124
117
|
else:
|
|
125
118
|
raise ValueError(f"不支持的通道后端: {backend}")
|
|
126
119
|
|
|
127
120
|
self._initialized = True
|
|
128
|
-
logger.info(f"通道管理器 [{self.name}] 初始化完成: {backend.value}")
|
|
121
|
+
logger.info(f"通道管理器 [{self.name}] 初始化完成: {backend.value}, url={self._mask_url(url)}")
|
|
129
122
|
return self
|
|
130
123
|
|
|
124
|
+
def _mask_url(self, url: str) -> str:
|
|
125
|
+
"""URL 脱敏(隐藏密码)。"""
|
|
126
|
+
if "@" in url:
|
|
127
|
+
parts = url.split("@")
|
|
128
|
+
prefix = parts[0]
|
|
129
|
+
suffix = parts[1]
|
|
130
|
+
if ":" in prefix:
|
|
131
|
+
scheme_and_user = prefix.rsplit(":", 1)[0]
|
|
132
|
+
return f"{scheme_and_user}:***@{suffix}"
|
|
133
|
+
return url
|
|
134
|
+
|
|
131
135
|
@property
|
|
132
136
|
def backend(self) -> IChannel:
|
|
133
137
|
"""获取通道后端。"""
|
|
@@ -218,9 +222,6 @@ class ChannelManager:
|
|
|
218
222
|
if self._backend:
|
|
219
223
|
await self._backend.close()
|
|
220
224
|
self._backend = None
|
|
221
|
-
if self._redis_client:
|
|
222
|
-
await self._redis_client.cleanup()
|
|
223
|
-
self._redis_client = None
|
|
224
225
|
self._initialized = False
|
|
225
226
|
logger.info(f"通道管理器 [{self.name}] 已关闭")
|
|
226
227
|
|
|
@@ -3,12 +3,11 @@
|
|
|
3
3
|
提供发布/订阅模式的事件总线功能,用于模块间解耦通信。
|
|
4
4
|
|
|
5
5
|
支持的后端:
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
- rabbitmq: RabbitMQ Exchange(分布式)
|
|
6
|
+
- broadcaster: 基于 broadcaster 库(推荐,支持 memory/redis/kafka/postgres)
|
|
7
|
+
- rabbitmq: RabbitMQ Exchange(复杂消息场景)
|
|
9
8
|
"""
|
|
10
9
|
|
|
11
|
-
from .backends import
|
|
10
|
+
from .backends import BroadcasterEventBus, RabbitMQEventBus
|
|
12
11
|
from .base import Event, EventBackend, EventHandler, EventType, IEventBus
|
|
13
12
|
from .manager import EventBusManager
|
|
14
13
|
|
|
@@ -22,9 +21,8 @@ __all__ = [
|
|
|
22
21
|
"EventType",
|
|
23
22
|
"IEventBus",
|
|
24
23
|
# 后端实现
|
|
25
|
-
"
|
|
24
|
+
"BroadcasterEventBus",
|
|
26
25
|
"RabbitMQEventBus",
|
|
27
|
-
"RedisEventBus",
|
|
28
26
|
]
|
|
29
27
|
|
|
30
28
|
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
"""事件总线后端实现。"""
|
|
2
2
|
|
|
3
|
-
from .
|
|
3
|
+
from .broadcaster import BroadcasterEventBus
|
|
4
4
|
from .rabbitmq import RabbitMQEventBus
|
|
5
|
-
from .redis import RedisEventBus
|
|
6
5
|
|
|
7
6
|
__all__ = [
|
|
8
|
-
"
|
|
7
|
+
"BroadcasterEventBus",
|
|
9
8
|
"RabbitMQEventBus",
|
|
10
|
-
"RedisEventBus",
|
|
11
9
|
]
|