aury-boot 0.0.15__tar.gz → 0.0.17__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.15 → aury_boot-0.0.17}/PKG-INFO +1 -1
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/_version.py +2 -2
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/app/components.py +50 -3
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/app/startup.py +1 -1
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/config/settings.py +31 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/AGENTS.md.tpl +12 -0
- aury_boot-0.0.17/aury/boot/commands/templates/project/aury_docs/08-scheduler.md.tpl +178 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/99-cli.md.tpl +1 -1
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/modules/schedules.py.tpl +4 -1
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/cache/manager.py +5 -1
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/scheduler/manager.py +125 -128
- aury_boot-0.0.15/aury/boot/commands/templates/project/aury_docs/08-scheduler.md.tpl +0 -32
- {aury_boot-0.0.15 → aury_boot-0.0.17}/.gitignore +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/README.md +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/adapter/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/adapter/base.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/adapter/config.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/adapter/decorators.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/adapter/exceptions.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/adapter/http.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/app/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/app/base.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/app/middlewares.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/config/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/config/multi_instance.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/constants/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/constants/components.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/constants/scheduler.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/constants/service.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/errors/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/errors/chain.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/errors/codes.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/errors/exceptions.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/errors/handlers.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/errors/response.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/interfaces/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/interfaces/egress.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/interfaces/ingress.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/middleware/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/middleware/logging.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/migrations/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/migrations/manager.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/migrations/setup.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/rpc/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/rpc/base.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/rpc/client.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/rpc/discovery.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/scheduler/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/scheduler/runner.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/application/server/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/add.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/app.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/config.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/docker.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/docs.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/generate.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/init.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/migrate/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/migrate/app.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/migrate/commands.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/pkg.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/scheduler.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/server/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/server/app.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/generate/api.py.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/generate/model.py.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/generate/repository.py.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/generate/schema.py.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/generate/service.py.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/README.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/admin_console_init.py.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/00-overview.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/01-model.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/02-repository.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/03-service.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/04-schema.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/05-api.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/06-exception.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/07-cache.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/09-tasks.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/10-storage.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/11-logging.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/12-admin.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/13-channel.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/14-mq.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/15-events.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/16-adapter.md.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/config.py.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/conftest.py.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/env_templates/_header.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/env_templates/admin.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/env_templates/cache.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/env_templates/database.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/env_templates/log.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/env_templates/messaging.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/env_templates/rpc.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/env_templates/scheduler.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/env_templates/service.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/env_templates/storage.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/env_templates/third_party.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/gitignore.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/main.py.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/modules/api.py.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/modules/exceptions.py.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/modules/tasks.py.tpl +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/worker.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/common/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/common/exceptions/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/common/i18n/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/common/i18n/translator.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/common/logging/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/common/logging/context.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/common/logging/decorators.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/common/logging/format.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/common/logging/setup.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/contrib/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/contrib/admin_console/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/contrib/admin_console/auth.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/contrib/admin_console/discovery.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/contrib/admin_console/install.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/contrib/admin_console/utils.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/domain/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/domain/exceptions/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/domain/models/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/domain/models/base.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/domain/models/mixins.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/domain/models/models.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/domain/pagination/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/domain/repository/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/domain/repository/impl.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/domain/repository/interceptors.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/domain/repository/interface.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/domain/repository/query_builder.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/domain/service/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/domain/service/base.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/domain/transaction/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/cache/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/cache/backends.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/cache/base.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/cache/exceptions.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/cache/factory.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/channel/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/channel/backends/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/channel/backends/memory.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/channel/backends/redis.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/channel/base.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/channel/manager.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/clients/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/clients/rabbitmq/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/clients/rabbitmq/config.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/clients/rabbitmq/manager.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/clients/redis/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/clients/redis/config.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/clients/redis/manager.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/database/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/database/config.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/database/exceptions.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/database/manager.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/database/query_tools/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/database/strategies/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/di/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/di/container.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/events/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/events/backends/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/events/backends/memory.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/events/backends/rabbitmq.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/events/backends/redis.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/events/base.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/events/manager.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/events/middleware.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/monitoring/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/mq/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/mq/backends/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/mq/backends/rabbitmq.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/mq/backends/redis.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/mq/base.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/mq/manager.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/scheduler/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/scheduler/exceptions.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/storage/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/storage/base.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/storage/exceptions.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/storage/factory.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/tasks/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/tasks/config.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/tasks/constants.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/tasks/exceptions.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/infrastructure/tasks/manager.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/testing/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/testing/base.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/testing/client.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/testing/factory.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/toolkit/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/toolkit/http/__init__.py +0 -0
- {aury_boot-0.0.15 → aury_boot-0.0.17}/pyproject.toml +0 -0
|
@@ -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.17'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 0, 17)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -281,18 +281,65 @@ class SchedulerComponent(Component):
|
|
|
281
281
|
except Exception as e:
|
|
282
282
|
logger.warning(f"加载定时任务模块失败 ({module_name}): {e}")
|
|
283
283
|
|
|
284
|
+
def _build_scheduler_config(self, config: BaseConfig) -> dict:
|
|
285
|
+
"""根据配置构建 APScheduler 初始化参数。"""
|
|
286
|
+
scheduler_kwargs: dict = {}
|
|
287
|
+
scheduler_config = config.scheduler
|
|
288
|
+
|
|
289
|
+
# jobstores: 根据 URL 自动选择存储后端
|
|
290
|
+
if scheduler_config.jobstore_url:
|
|
291
|
+
url = scheduler_config.jobstore_url
|
|
292
|
+
if url.startswith("redis://"):
|
|
293
|
+
try:
|
|
294
|
+
from apscheduler.jobstores.redis import RedisJobStore
|
|
295
|
+
scheduler_kwargs["jobstores"] = {
|
|
296
|
+
"default": RedisJobStore.from_url(url)
|
|
297
|
+
}
|
|
298
|
+
logger.info(f"调度器使用 Redis 存储: {url.split('@')[-1]}")
|
|
299
|
+
except ImportError:
|
|
300
|
+
logger.warning("Redis jobstore 需要安装 redis: pip install redis")
|
|
301
|
+
else:
|
|
302
|
+
# SQLAlchemy 存储 (sqlite/postgresql/mysql)
|
|
303
|
+
try:
|
|
304
|
+
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
|
|
305
|
+
scheduler_kwargs["jobstores"] = {
|
|
306
|
+
"default": SQLAlchemyJobStore(url=url)
|
|
307
|
+
}
|
|
308
|
+
logger.info("调度器使用 SQLAlchemy 存储")
|
|
309
|
+
except ImportError:
|
|
310
|
+
logger.warning("SQLAlchemy jobstore 需要安装 sqlalchemy")
|
|
311
|
+
|
|
312
|
+
# timezone
|
|
313
|
+
if scheduler_config.timezone:
|
|
314
|
+
scheduler_kwargs["timezone"] = scheduler_config.timezone
|
|
315
|
+
|
|
316
|
+
# job_defaults
|
|
317
|
+
scheduler_kwargs["job_defaults"] = {
|
|
318
|
+
"coalesce": scheduler_config.coalesce,
|
|
319
|
+
"max_instances": scheduler_config.max_instances,
|
|
320
|
+
"misfire_grace_time": scheduler_config.misfire_grace_time,
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return scheduler_kwargs
|
|
324
|
+
|
|
284
325
|
async def setup(self, app: FoundationApp, config: BaseConfig) -> None:
|
|
285
326
|
"""启动调度器。
|
|
286
327
|
|
|
287
|
-
1.
|
|
288
|
-
2.
|
|
328
|
+
1. 根据配置初始化调度器(jobstore/timezone/job_defaults)
|
|
329
|
+
2. 自动发现并加载定时任务模块
|
|
330
|
+
3. 启动调度器(注册装饰器收集的任务)
|
|
289
331
|
"""
|
|
290
332
|
try:
|
|
333
|
+
# 构建配置
|
|
334
|
+
scheduler_kwargs = self._build_scheduler_config(config)
|
|
335
|
+
|
|
336
|
+
# 获取/创建调度器实例
|
|
337
|
+
scheduler = SchedulerManager.get_instance("default", **scheduler_kwargs)
|
|
338
|
+
|
|
291
339
|
# 自动发现并加载定时任务模块
|
|
292
340
|
self._autodiscover_schedules(app, config)
|
|
293
341
|
|
|
294
342
|
# 启动调度器
|
|
295
|
-
scheduler = SchedulerManager.get_instance()
|
|
296
343
|
scheduler.start()
|
|
297
344
|
except Exception as e:
|
|
298
345
|
logger.warning(f"调度器启动失败(非关键): {e}")
|
|
@@ -152,7 +152,7 @@ def collect_component_status() -> list[ComponentStatus]:
|
|
|
152
152
|
name="Cache" if name == "default" else f"Cache [{name}]",
|
|
153
153
|
status="ok",
|
|
154
154
|
backend=instance.backend_type,
|
|
155
|
-
url=instance._config.get("CACHE_URL")
|
|
155
|
+
url=(instance._config or {}).get("CACHE_URL"),
|
|
156
156
|
)
|
|
157
157
|
)
|
|
158
158
|
|
|
@@ -416,6 +416,10 @@ class SchedulerSettings(BaseModel):
|
|
|
416
416
|
- SCHEDULER__ENABLED=false: 只运行 API,不启动调度器
|
|
417
417
|
|
|
418
418
|
独立调度器通过 `aury scheduler` 命令运行,不需要此配置。
|
|
419
|
+
|
|
420
|
+
分布式调度:
|
|
421
|
+
- 配置 SCHEDULER__JOBSTORE_URL 使用 Redis/SQLAlchemy 存储
|
|
422
|
+
- 多节点部署时共享任务状态
|
|
419
423
|
"""
|
|
420
424
|
|
|
421
425
|
enabled: bool = Field(
|
|
@@ -426,6 +430,33 @@ class SchedulerSettings(BaseModel):
|
|
|
426
430
|
default_factory=list,
|
|
427
431
|
description="定时任务模块列表。为空时自动发现 schedules 模块"
|
|
428
432
|
)
|
|
433
|
+
# APScheduler 配置
|
|
434
|
+
jobstore_url: str | None = Field(
|
|
435
|
+
default=None,
|
|
436
|
+
description=(
|
|
437
|
+
"任务存储 URL。支持:\n"
|
|
438
|
+
"- redis://localhost:6379/0(Redis 存储)\n"
|
|
439
|
+
"- sqlite:///jobs.db(SQLite 存储)\n"
|
|
440
|
+
"- postgresql://user:pass@host/db(PostgreSQL 存储)\n"
|
|
441
|
+
"- 不配置则使用内存存储"
|
|
442
|
+
)
|
|
443
|
+
)
|
|
444
|
+
timezone: str | None = Field(
|
|
445
|
+
default=None,
|
|
446
|
+
description="调度器时区,如 Asia/Shanghai、UTC"
|
|
447
|
+
)
|
|
448
|
+
coalesce: bool = Field(
|
|
449
|
+
default=True,
|
|
450
|
+
description="是否合并错过的任务执行(多次错过只执行一次)"
|
|
451
|
+
)
|
|
452
|
+
max_instances: int = Field(
|
|
453
|
+
default=1,
|
|
454
|
+
description="同一任务的最大并发实例数"
|
|
455
|
+
)
|
|
456
|
+
misfire_grace_time: int = Field(
|
|
457
|
+
default=60,
|
|
458
|
+
description="任务错过容忍时间(秒),超过此时间则跳过"
|
|
459
|
+
)
|
|
429
460
|
|
|
430
461
|
|
|
431
462
|
class TaskSettings(BaseModel):
|
|
@@ -122,6 +122,8 @@ mypy {package_name}/
|
|
|
122
122
|
|
|
123
123
|
## 代码规范
|
|
124
124
|
|
|
125
|
+
> 项目所有业务配置请通过应用 `settings`/配置对象获取,**不要**直接使用 `os.environ` 在业务代码中读环境变量。
|
|
126
|
+
|
|
125
127
|
### Model 规范
|
|
126
128
|
|
|
127
129
|
- **必须**继承框架预定义基类,**不要**直接继承 `Base`
|
|
@@ -129,6 +131,16 @@ mypy {package_name}/
|
|
|
129
131
|
- 软删除模型**必须**使用复合唯一约束(包含 `deleted_at`),不能单独使用 `unique=True`
|
|
130
132
|
- **不建议**使用数据库外键(`ForeignKey`),通过程序控制关系,便于分库分表和微服务拆分
|
|
131
133
|
|
|
134
|
+
**重要:软删除机制**
|
|
135
|
+
|
|
136
|
+
框架采用「默认 0」策略,而非 IS NULL:
|
|
137
|
+
- `deleted_at = 0`:未删除
|
|
138
|
+
- `deleted_at > 0`:已删除(Unix 时间戳)
|
|
139
|
+
|
|
140
|
+
查询未删除记录时,使用 `WHERE deleted_at = 0`,不是 `WHERE deleted_at IS NULL`。
|
|
141
|
+
|
|
142
|
+
BaseRepository 已自动处理软删除过滤,无需手动添加条件。
|
|
143
|
+
|
|
132
144
|
```python
|
|
133
145
|
# ✅ 正确
|
|
134
146
|
from aury.boot.domain.models import AuditableStateModel
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# 定时任务(Scheduler)
|
|
2
|
+
|
|
3
|
+
基于 APScheduler,完全透传原生 API。
|
|
4
|
+
|
|
5
|
+
## 基本用法
|
|
6
|
+
|
|
7
|
+
**文件**: `{package_name}/schedules/__init__.py`
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
"""定时任务模块。"""
|
|
11
|
+
|
|
12
|
+
from apscheduler.triggers.cron import CronTrigger
|
|
13
|
+
from apscheduler.triggers.interval import IntervalTrigger
|
|
14
|
+
|
|
15
|
+
from aury.boot.common.logging import logger
|
|
16
|
+
from aury.boot.infrastructure.scheduler import SchedulerManager
|
|
17
|
+
|
|
18
|
+
scheduler = SchedulerManager.get_instance()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@scheduler.scheduled_job(IntervalTrigger(seconds=60))
|
|
22
|
+
async def every_minute():
|
|
23
|
+
"""每 60 秒执行。"""
|
|
24
|
+
logger.info("定时任务执行中...")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@scheduler.scheduled_job(CronTrigger(hour=0, minute=0))
|
|
28
|
+
async def daily_task():
|
|
29
|
+
"""每天凌晨执行。"""
|
|
30
|
+
logger.info("每日任务执行中...")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@scheduler.scheduled_job(CronTrigger(day_of_week="mon", hour=9))
|
|
34
|
+
async def weekly_report():
|
|
35
|
+
"""每周一 9 点执行。"""
|
|
36
|
+
logger.info("周报任务执行中...")
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
启用方式:配置 `SCHEDULER__ENABLED=true`,框架自动加载 `{package_name}/schedules/` 模块。
|
|
40
|
+
|
|
41
|
+
## 配置项
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# .env
|
|
45
|
+
SCHEDULER__ENABLED=true # 是否启用
|
|
46
|
+
SCHEDULER__TIMEZONE=Asia/Shanghai # 时区
|
|
47
|
+
SCHEDULER__COALESCE=true # 合并错过的任务
|
|
48
|
+
SCHEDULER__MAX_INSTANCES=1 # 同一任务最大并发数
|
|
49
|
+
SCHEDULER__MISFIRE_GRACE_TIME=60 # 错过容忍时间(秒)
|
|
50
|
+
SCHEDULER__JOBSTORE_URL=redis://localhost:6379/0 # 分布式存储(可选)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 触发器类型
|
|
54
|
+
|
|
55
|
+
### CronTrigger - 定时触发
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from apscheduler.triggers.cron import CronTrigger
|
|
59
|
+
|
|
60
|
+
# 每天凌晨 2:30
|
|
61
|
+
CronTrigger(hour=2, minute=30)
|
|
62
|
+
|
|
63
|
+
# 每小时整点
|
|
64
|
+
CronTrigger(hour="*", minute=0)
|
|
65
|
+
|
|
66
|
+
# 工作日 9:00
|
|
67
|
+
CronTrigger(day_of_week="mon-fri", hour=9)
|
|
68
|
+
|
|
69
|
+
# 每月 1 号
|
|
70
|
+
CronTrigger(day=1, hour=0)
|
|
71
|
+
|
|
72
|
+
# 使用 crontab 表达式
|
|
73
|
+
CronTrigger.from_crontab("0 2 * * *") # 每天 2:00
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### IntervalTrigger - 间隔触发
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from apscheduler.triggers.interval import IntervalTrigger
|
|
80
|
+
|
|
81
|
+
IntervalTrigger(seconds=30) # 每 30 秒
|
|
82
|
+
IntervalTrigger(minutes=5) # 每 5 分钟
|
|
83
|
+
IntervalTrigger(hours=1) # 每小时
|
|
84
|
+
IntervalTrigger(days=1) # 每天
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### DateTrigger - 一次性触发
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from apscheduler.triggers.date import DateTrigger
|
|
91
|
+
from datetime import datetime, timedelta
|
|
92
|
+
|
|
93
|
+
# 10 秒后执行
|
|
94
|
+
DateTrigger(run_date=datetime.now() + timedelta(seconds=10))
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## 多实例支持
|
|
98
|
+
|
|
99
|
+
支持不同业务线使用独立的调度器实例:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
# 默认实例
|
|
103
|
+
scheduler = SchedulerManager.get_instance()
|
|
104
|
+
|
|
105
|
+
# 命名实例
|
|
106
|
+
report_scheduler = SchedulerManager.get_instance("report")
|
|
107
|
+
cleanup_scheduler = SchedulerManager.get_instance("cleanup")
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 分布式调度
|
|
111
|
+
|
|
112
|
+
多节点部署时,配置相同的 `SCHEDULER__JOBSTORE_URL`,所有节点共享任务状态:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# 所有节点使用相同配置
|
|
116
|
+
SCHEDULER__JOBSTORE_URL=redis://redis:6379/0
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
APScheduler 自动协调防止重复执行。
|
|
120
|
+
|
|
121
|
+
### 代码方式配置(高级)
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from apscheduler.jobstores.redis import RedisJobStore
|
|
125
|
+
from apscheduler.executors.asyncio import AsyncIOExecutor
|
|
126
|
+
|
|
127
|
+
scheduler = SchedulerManager.get_instance(
|
|
128
|
+
"distributed",
|
|
129
|
+
jobstores={"default": RedisJobStore(host="localhost", port=6379)},
|
|
130
|
+
executors={"default": AsyncIOExecutor()},
|
|
131
|
+
job_defaults={"coalesce": True, "max_instances": 1},
|
|
132
|
+
timezone="Asia/Shanghai",
|
|
133
|
+
)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## 任务管理
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
# 添加任务
|
|
140
|
+
scheduler.add_job(my_task, CronTrigger(hour=2), id="my_task")
|
|
141
|
+
|
|
142
|
+
# 获取任务
|
|
143
|
+
job = scheduler.get_job("my_task")
|
|
144
|
+
jobs = scheduler.get_jobs()
|
|
145
|
+
|
|
146
|
+
# 暂停/恢复
|
|
147
|
+
scheduler.pause_job("my_task")
|
|
148
|
+
scheduler.resume_job("my_task")
|
|
149
|
+
|
|
150
|
+
# 移除
|
|
151
|
+
scheduler.remove_job("my_task")
|
|
152
|
+
|
|
153
|
+
# 重新调度
|
|
154
|
+
scheduler.reschedule_job("my_task", CronTrigger(hour=3))
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## 监听器(高级)
|
|
158
|
+
|
|
159
|
+
通过底层 APScheduler 实例访问:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from apscheduler.events import EVENT_JOB_EXECUTED, EVENT_JOB_ERROR
|
|
163
|
+
|
|
164
|
+
def job_listener(event):
|
|
165
|
+
if event.exception:
|
|
166
|
+
logger.error(f"任务失败: {event.job_id}")
|
|
167
|
+
else:
|
|
168
|
+
logger.info(f"任务完成: {event.job_id}")
|
|
169
|
+
|
|
170
|
+
scheduler.scheduler.add_listener(job_listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## 实践建议
|
|
174
|
+
|
|
175
|
+
1. **使用明确的 ID**:便于管理和调试
|
|
176
|
+
2. **合理设置间隔**:避免太频繁的任务
|
|
177
|
+
3. **异常处理**:在任务函数内捕获异常,避免影响调度器
|
|
178
|
+
4. **超时保护**:长运行任务使用 `asyncio.wait_for`
|
{aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/aury_docs/99-cli.md.tpl
RENAMED
|
@@ -153,7 +153,7 @@ register_commands(app)
|
|
|
153
153
|
@app.command()
|
|
154
154
|
async def hello(name: str = "world") -> None:
|
|
155
155
|
"""示例:项目自定义命令。"""
|
|
156
|
-
print(f"Hello, {name} from {project_name_snake}!")
|
|
156
|
+
print(f"Hello, {{name}} from {project_name_snake}!")
|
|
157
157
|
```
|
|
158
158
|
|
|
159
159
|
> 注意:这里的 `app` 是 Typer 应用实例,`register_commands` 会把所有内置的 `init/generate/server/...` 等命令挂到你自己的 CLI 下。
|
{aury_boot-0.0.15 → aury_boot-0.0.17}/aury/boot/commands/templates/project/modules/schedules.py.tpl
RENAMED
|
@@ -6,13 +6,16 @@
|
|
|
6
6
|
也可通过 SCHEDULER_SCHEDULE_MODULES 环境变量指定自定义模块。
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
+
# from apscheduler.triggers.cron import CronTrigger
|
|
10
|
+
# from apscheduler.triggers.interval import IntervalTrigger
|
|
11
|
+
#
|
|
9
12
|
# from aury.boot.common.logging import logger
|
|
10
13
|
# from aury.boot.infrastructure.scheduler import SchedulerManager
|
|
11
14
|
#
|
|
12
15
|
# scheduler = SchedulerManager.get_instance()
|
|
13
16
|
#
|
|
14
17
|
#
|
|
15
|
-
# @scheduler.scheduled_job(
|
|
18
|
+
# @scheduler.scheduled_job(IntervalTrigger(seconds=60))
|
|
16
19
|
# async def example_job():
|
|
17
20
|
# """示例定时任务,每 60 秒执行一次。"""
|
|
18
21
|
# logger.info("定时任务执行中...")
|
|
@@ -110,13 +110,15 @@ class CacheManager:
|
|
|
110
110
|
supported = ", ".join(b.value for b in CacheBackend)
|
|
111
111
|
raise ValueError(f"不支持的缓存后端: {backend}。支持: {supported}")
|
|
112
112
|
|
|
113
|
-
#
|
|
113
|
+
# 保存配置(用于启动横幅等场景展示)
|
|
114
114
|
self._config = {"CACHE_TYPE": backend.value}
|
|
115
115
|
|
|
116
116
|
# 根据后端类型构建配置并创建后端
|
|
117
117
|
if backend == CacheBackend.REDIS:
|
|
118
118
|
if not url:
|
|
119
119
|
raise ValueError("Redis 缓存需要提供 url 参数")
|
|
120
|
+
# 记录 URL 以便在启动横幅中展示(会通过 mask_url 脱敏)
|
|
121
|
+
self._config["CACHE_URL"] = url
|
|
120
122
|
self._backend = await CacheFactory.create(
|
|
121
123
|
"redis", url=url, serializer=serializer
|
|
122
124
|
)
|
|
@@ -128,6 +130,8 @@ class CacheManager:
|
|
|
128
130
|
cache_url = url or (servers[0] if servers else None)
|
|
129
131
|
if not cache_url:
|
|
130
132
|
raise ValueError("Memcached 缓存需要提供 url 参数")
|
|
133
|
+
# 同样记录 URL,便于在启动横幅中展示
|
|
134
|
+
self._config["CACHE_URL"] = cache_url
|
|
131
135
|
self._backend = await CacheFactory.create(
|
|
132
136
|
"memcached", servers=cache_url
|
|
133
137
|
)
|