aury-boot 0.0.18__tar.gz → 0.0.20__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.18 → aury_boot-0.0.20}/PKG-INFO +1 -1
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/_version.py +2 -2
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/08-scheduler.md.tpl +57 -26
- aury_boot-0.0.20/aury/boot/commands/templates/project/modules/schedules.py.tpl +38 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/scheduler/manager.py +179 -36
- aury_boot-0.0.18/aury/boot/commands/templates/project/modules/schedules.py.tpl +0 -21
- {aury_boot-0.0.18 → aury_boot-0.0.20}/.gitignore +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/README.md +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/adapter/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/adapter/base.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/adapter/config.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/adapter/decorators.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/adapter/exceptions.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/adapter/http.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/app/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/app/base.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/app/components.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/app/middlewares.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/app/startup.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/config/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/config/multi_instance.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/config/settings.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/constants/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/constants/components.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/constants/scheduler.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/constants/service.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/errors/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/errors/chain.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/errors/codes.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/errors/exceptions.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/errors/handlers.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/errors/response.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/interfaces/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/interfaces/egress.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/interfaces/ingress.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/middleware/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/middleware/logging.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/migrations/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/migrations/manager.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/migrations/setup.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/rpc/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/rpc/base.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/rpc/client.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/rpc/discovery.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/scheduler/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/scheduler/runner.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/application/server/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/add.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/app.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/config.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/docker.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/docs.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/generate.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/init.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/migrate/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/migrate/app.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/migrate/commands.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/pkg.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/scheduler.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/server/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/server/app.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/generate/api.py.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/generate/model.py.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/generate/repository.py.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/generate/schema.py.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/generate/service.py.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/AGENTS.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/README.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/admin_console_init.py.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/00-overview.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/01-model.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/02-repository.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/03-service.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/04-schema.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/05-api.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/06-exception.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/07-cache.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/09-tasks.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/10-storage.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/11-logging.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/12-admin.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/13-channel.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/14-mq.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/15-events.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/16-adapter.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/aury_docs/99-cli.md.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/config.py.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/conftest.py.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/env_templates/_header.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/env_templates/admin.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/env_templates/cache.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/env_templates/database.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/env_templates/log.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/env_templates/messaging.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/env_templates/rpc.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/env_templates/scheduler.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/env_templates/service.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/env_templates/storage.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/env_templates/third_party.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/gitignore.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/main.py.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/modules/api.py.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/modules/exceptions.py.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/templates/project/modules/tasks.py.tpl +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/commands/worker.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/common/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/common/exceptions/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/common/i18n/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/common/i18n/translator.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/common/logging/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/common/logging/context.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/common/logging/decorators.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/common/logging/format.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/common/logging/setup.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/contrib/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/contrib/admin_console/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/contrib/admin_console/auth.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/contrib/admin_console/discovery.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/contrib/admin_console/install.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/contrib/admin_console/utils.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/domain/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/domain/exceptions/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/domain/models/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/domain/models/base.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/domain/models/mixins.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/domain/models/models.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/domain/pagination/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/domain/repository/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/domain/repository/impl.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/domain/repository/interceptors.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/domain/repository/interface.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/domain/repository/query_builder.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/domain/service/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/domain/service/base.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/domain/transaction/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/cache/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/cache/backends.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/cache/base.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/cache/exceptions.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/cache/factory.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/cache/manager.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/channel/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/channel/backends/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/channel/backends/memory.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/channel/backends/redis.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/channel/base.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/channel/manager.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/clients/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/clients/rabbitmq/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/clients/rabbitmq/config.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/clients/rabbitmq/manager.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/clients/redis/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/clients/redis/config.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/clients/redis/manager.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/database/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/database/config.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/database/exceptions.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/database/manager.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/database/query_tools/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/database/strategies/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/di/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/di/container.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/events/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/events/backends/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/events/backends/memory.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/events/backends/rabbitmq.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/events/backends/redis.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/events/base.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/events/manager.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/events/middleware.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/monitoring/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/mq/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/mq/backends/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/mq/backends/rabbitmq.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/mq/backends/redis.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/mq/base.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/mq/manager.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/scheduler/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/scheduler/exceptions.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/storage/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/storage/base.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/storage/exceptions.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/storage/factory.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/tasks/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/tasks/config.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/tasks/constants.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/tasks/exceptions.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/infrastructure/tasks/manager.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/testing/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/testing/base.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/testing/client.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/testing/factory.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/toolkit/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/aury/boot/toolkit/http/__init__.py +0 -0
- {aury_boot-0.0.18 → aury_boot-0.0.20}/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.20'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 0, 20)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 定时任务(Scheduler)
|
|
2
2
|
|
|
3
|
-
基于 APScheduler
|
|
3
|
+
基于 APScheduler,支持两种触发器语法:字符串模式和原生对象模式。
|
|
4
4
|
|
|
5
5
|
## 基本用法
|
|
6
6
|
|
|
@@ -9,31 +9,38 @@
|
|
|
9
9
|
```python
|
|
10
10
|
"""定时任务模块。"""
|
|
11
11
|
|
|
12
|
-
from apscheduler.triggers.cron import CronTrigger
|
|
13
|
-
from apscheduler.triggers.interval import IntervalTrigger
|
|
14
|
-
|
|
15
12
|
from aury.boot.common.logging import logger
|
|
16
13
|
from aury.boot.infrastructure.scheduler import SchedulerManager
|
|
17
14
|
|
|
18
15
|
scheduler = SchedulerManager.get_instance()
|
|
19
16
|
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
# === 字符串模式(推荐,简洁)===
|
|
19
|
+
@scheduler.scheduled_job("interval", seconds=60)
|
|
22
20
|
async def every_minute():
|
|
23
21
|
"""每 60 秒执行。"""
|
|
24
22
|
logger.info("定时任务执行中...")
|
|
25
23
|
|
|
26
24
|
|
|
27
|
-
@scheduler.scheduled_job(
|
|
25
|
+
@scheduler.scheduled_job("cron", hour=0, minute=0)
|
|
28
26
|
async def daily_task():
|
|
29
27
|
"""每天凌晨执行。"""
|
|
30
28
|
logger.info("每日任务执行中...")
|
|
31
29
|
|
|
32
30
|
|
|
33
|
-
@scheduler.scheduled_job(
|
|
31
|
+
@scheduler.scheduled_job("cron", day_of_week="mon", hour=9)
|
|
34
32
|
async def weekly_report():
|
|
35
33
|
"""每周一 9 点执行。"""
|
|
36
34
|
logger.info("周报任务执行中...")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# === 原生对象模式(完整功能)===
|
|
38
|
+
from apscheduler.triggers.cron import CronTrigger
|
|
39
|
+
|
|
40
|
+
@scheduler.scheduled_job(CronTrigger.from_crontab("0 2 * * *"))
|
|
41
|
+
async def crontab_task():
|
|
42
|
+
"""每天凌晨 2 点执行(使用 crontab 表达式)。"""
|
|
43
|
+
logger.info("每日任务执行中...")
|
|
37
44
|
```
|
|
38
45
|
|
|
39
46
|
启用方式:配置 `SCHEDULER__ENABLED=true`,框架自动加载 `{package_name}/schedules/` 模块。
|
|
@@ -50,40 +57,57 @@ SCHEDULER__MISFIRE_GRACE_TIME=60 # 错过容忍时间(秒)
|
|
|
50
57
|
SCHEDULER__JOBSTORE_URL=redis://localhost:6379/0 # 分布式存储(可选)
|
|
51
58
|
```
|
|
52
59
|
|
|
53
|
-
##
|
|
60
|
+
## 触发器语法
|
|
54
61
|
|
|
55
|
-
|
|
62
|
+
支持两种语法:
|
|
56
63
|
|
|
57
|
-
|
|
58
|
-
|
|
64
|
+
| 语法 | 适用场景 | 示例 |
|
|
65
|
+
|------|---------|------|
|
|
66
|
+
| 字符串模式 | 日常使用,简洁 | `"cron", hour="*", minute=0` |
|
|
67
|
+
| 原生对象 | crontab 表达式、复杂配置 | `CronTrigger.from_crontab("0 * * * *")` |
|
|
59
68
|
|
|
69
|
+
### cron - 定时触发
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
# === 字符串模式 ===
|
|
60
73
|
# 每天凌晨 2:30
|
|
61
|
-
|
|
74
|
+
@scheduler.scheduled_job("cron", hour=2, minute=30)
|
|
62
75
|
|
|
63
76
|
# 每小时整点
|
|
64
|
-
|
|
77
|
+
@scheduler.scheduled_job("cron", hour="*", minute=0)
|
|
65
78
|
|
|
66
79
|
# 工作日 9:00
|
|
67
|
-
|
|
80
|
+
@scheduler.scheduled_job("cron", day_of_week="mon-fri", hour=9)
|
|
68
81
|
|
|
69
82
|
# 每月 1 号
|
|
70
|
-
|
|
83
|
+
@scheduler.scheduled_job("cron", day=1, hour=0)
|
|
84
|
+
|
|
85
|
+
# === 原生对象模式 ===
|
|
86
|
+
from apscheduler.triggers.cron import CronTrigger
|
|
71
87
|
|
|
72
88
|
# 使用 crontab 表达式
|
|
73
|
-
CronTrigger.from_crontab("0 2 * * *") # 每天 2:00
|
|
89
|
+
@scheduler.scheduled_job(CronTrigger.from_crontab("0 2 * * *")) # 每天 2:00
|
|
74
90
|
```
|
|
75
91
|
|
|
76
|
-
|
|
92
|
+
**cron 参数**:`year`, `month`, `day`, `week`, `day_of_week`, `hour`, `minute`, `second`, `start_date`, `end_date`, `timezone`, `jitter`
|
|
93
|
+
|
|
94
|
+
### interval - 间隔触发
|
|
77
95
|
|
|
78
96
|
```python
|
|
97
|
+
# === 字符串模式 ===
|
|
98
|
+
@scheduler.scheduled_job("interval", seconds=30) # 每 30 秒
|
|
99
|
+
@scheduler.scheduled_job("interval", minutes=5) # 每 5 分钟
|
|
100
|
+
@scheduler.scheduled_job("interval", hours=1) # 每小时
|
|
101
|
+
@scheduler.scheduled_job("interval", days=1) # 每天
|
|
102
|
+
|
|
103
|
+
# === 原生对象模式 ===
|
|
79
104
|
from apscheduler.triggers.interval import IntervalTrigger
|
|
80
105
|
|
|
81
|
-
IntervalTrigger(
|
|
82
|
-
IntervalTrigger(minutes=5) # 每 5 分钟
|
|
83
|
-
IntervalTrigger(hours=1) # 每小时
|
|
84
|
-
IntervalTrigger(days=1) # 每天
|
|
106
|
+
@scheduler.scheduled_job(IntervalTrigger(hours=1, jitter=60)) # 每小时,随机抖动 60 秒
|
|
85
107
|
```
|
|
86
108
|
|
|
109
|
+
**interval 参数**:`weeks`, `days`, `hours`, `minutes`, `seconds`, `start_date`, `end_date`, `timezone`, `jitter`
|
|
110
|
+
|
|
87
111
|
### DateTrigger - 一次性触发
|
|
88
112
|
|
|
89
113
|
```python
|
|
@@ -91,7 +115,7 @@ from apscheduler.triggers.date import DateTrigger
|
|
|
91
115
|
from datetime import datetime, timedelta
|
|
92
116
|
|
|
93
117
|
# 10 秒后执行
|
|
94
|
-
DateTrigger(run_date=datetime.now() + timedelta(seconds=10))
|
|
118
|
+
scheduler.add_job(my_task, DateTrigger(run_date=datetime.now() + timedelta(seconds=10)))
|
|
95
119
|
```
|
|
96
120
|
|
|
97
121
|
## 多实例支持
|
|
@@ -136,7 +160,11 @@ scheduler = SchedulerManager.get_instance(
|
|
|
136
160
|
## 任务管理
|
|
137
161
|
|
|
138
162
|
```python
|
|
139
|
-
#
|
|
163
|
+
# 添加任务(字符串模式)
|
|
164
|
+
scheduler.add_job(my_task, "cron", hour=2, minute=0, id="my_task")
|
|
165
|
+
|
|
166
|
+
# 添加任务(原生对象模式)
|
|
167
|
+
from apscheduler.triggers.cron import CronTrigger
|
|
140
168
|
scheduler.add_job(my_task, CronTrigger(hour=2), id="my_task")
|
|
141
169
|
|
|
142
170
|
# 获取任务
|
|
@@ -150,7 +178,10 @@ scheduler.resume_job("my_task")
|
|
|
150
178
|
# 移除
|
|
151
179
|
scheduler.remove_job("my_task")
|
|
152
180
|
|
|
153
|
-
#
|
|
181
|
+
# 重新调度(字符串模式)
|
|
182
|
+
scheduler.reschedule_job("my_task", "cron", hour=3)
|
|
183
|
+
|
|
184
|
+
# 重新调度(原生对象模式)
|
|
154
185
|
scheduler.reschedule_job("my_task", CronTrigger(hour=3))
|
|
155
186
|
```
|
|
156
187
|
|
|
@@ -163,9 +194,9 @@ from apscheduler.events import EVENT_JOB_EXECUTED, EVENT_JOB_ERROR
|
|
|
163
194
|
|
|
164
195
|
def job_listener(event):
|
|
165
196
|
if event.exception:
|
|
166
|
-
logger.error(f"任务失败: {event.job_id}")
|
|
197
|
+
logger.error(f"任务失败: {{event.job_id}}")
|
|
167
198
|
else:
|
|
168
|
-
logger.info(f"任务完成: {event.job_id}")
|
|
199
|
+
logger.info(f"任务完成: {{event.job_id}}")
|
|
169
200
|
|
|
170
201
|
scheduler.scheduler.add_listener(job_listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
|
|
171
202
|
```
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""定时任务模块(Scheduler)。
|
|
2
|
+
|
|
3
|
+
在此文件中定义定时任务,使用 @scheduler.scheduled_job() 装饰器。
|
|
4
|
+
|
|
5
|
+
框架会自动发现并加载本模块,无需在 main.py 中手动导入。
|
|
6
|
+
也可通过 SCHEDULER_SCHEDULE_MODULES 环境变量指定自定义模块。
|
|
7
|
+
|
|
8
|
+
触发器支持两种语法:
|
|
9
|
+
- 字符串模式(推荐):@scheduler.scheduled_job("cron", hour="*", minute=0)
|
|
10
|
+
- 原生对象模式:@scheduler.scheduled_job(CronTrigger(hour="*"))
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
# from aury.boot.common.logging import logger
|
|
14
|
+
# from aury.boot.infrastructure.scheduler import SchedulerManager
|
|
15
|
+
#
|
|
16
|
+
# scheduler = SchedulerManager.get_instance()
|
|
17
|
+
#
|
|
18
|
+
#
|
|
19
|
+
# # === 字符串模式(推荐,简洁)===
|
|
20
|
+
# @scheduler.scheduled_job("interval", seconds=60)
|
|
21
|
+
# async def example_job():
|
|
22
|
+
# """示例定时任务,每 60 秒执行一次。"""
|
|
23
|
+
# logger.info("定时任务执行中...")
|
|
24
|
+
#
|
|
25
|
+
#
|
|
26
|
+
# @scheduler.scheduled_job("cron", hour="*", minute=0)
|
|
27
|
+
# async def hourly_job():
|
|
28
|
+
# """每小时整点执行。"""
|
|
29
|
+
# logger.info("整点任务执行")
|
|
30
|
+
#
|
|
31
|
+
#
|
|
32
|
+
# # === 原生对象模式(完整功能)===
|
|
33
|
+
# # from apscheduler.triggers.cron import CronTrigger
|
|
34
|
+
# #
|
|
35
|
+
# # @scheduler.scheduled_job(CronTrigger.from_crontab("0 2 * * *"))
|
|
36
|
+
# # async def daily_job():
|
|
37
|
+
# # """每天凌晨 2 点执行(使用 crontab 表达式)。"""
|
|
38
|
+
# # logger.info("每日任务执行")
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
- 自动设置日志上下文(调度器任务日志自动写入 scheduler_xxx.log)
|
|
8
8
|
- 支持多个命名实例
|
|
9
9
|
- 支持 APScheduler 完整配置(jobstores、executors、job_defaults、timezone)
|
|
10
|
+
- 支持两种触发器语法:字符串模式和原生对象模式
|
|
10
11
|
"""
|
|
11
12
|
|
|
12
13
|
from __future__ import annotations
|
|
@@ -14,20 +15,32 @@ from __future__ import annotations
|
|
|
14
15
|
import asyncio
|
|
15
16
|
from collections.abc import Callable
|
|
16
17
|
from functools import wraps
|
|
17
|
-
from typing import TYPE_CHECKING, Any
|
|
18
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
18
19
|
|
|
19
20
|
from aury.boot.common.logging import logger, set_service_context
|
|
20
21
|
|
|
21
22
|
# 延迟导入 apscheduler(可选依赖)
|
|
22
23
|
try:
|
|
23
24
|
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
|
25
|
+
from apscheduler.triggers.base import BaseTrigger
|
|
26
|
+
from apscheduler.triggers.cron import CronTrigger
|
|
27
|
+
from apscheduler.triggers.interval import IntervalTrigger
|
|
24
28
|
_APSCHEDULER_AVAILABLE = True
|
|
25
29
|
except ImportError:
|
|
26
30
|
_APSCHEDULER_AVAILABLE = False
|
|
27
31
|
if TYPE_CHECKING:
|
|
28
32
|
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
|
33
|
+
from apscheduler.triggers.base import BaseTrigger
|
|
34
|
+
from apscheduler.triggers.cron import CronTrigger
|
|
35
|
+
from apscheduler.triggers.interval import IntervalTrigger
|
|
29
36
|
else:
|
|
30
37
|
AsyncIOScheduler = None
|
|
38
|
+
BaseTrigger = None
|
|
39
|
+
CronTrigger = None
|
|
40
|
+
IntervalTrigger = None
|
|
41
|
+
|
|
42
|
+
# 触发器类型别名
|
|
43
|
+
TriggerType = Literal["cron", "interval"]
|
|
31
44
|
|
|
32
45
|
|
|
33
46
|
class SchedulerManager:
|
|
@@ -39,6 +52,16 @@ class SchedulerManager:
|
|
|
39
52
|
- job_defaults: 任务默认配置(coalesce/max_instances/misfire_grace_time)
|
|
40
53
|
- timezone: 时区
|
|
41
54
|
|
|
55
|
+
触发器支持两种语法:
|
|
56
|
+
|
|
57
|
+
1. 字符串模式(简洁):
|
|
58
|
+
@scheduler.scheduled_job("cron", hour="*", minute=0)
|
|
59
|
+
@scheduler.scheduled_job("interval", seconds=60)
|
|
60
|
+
|
|
61
|
+
2. 原生对象模式(完整功能):
|
|
62
|
+
@scheduler.scheduled_job(CronTrigger(hour="*"))
|
|
63
|
+
@scheduler.scheduled_job(IntervalTrigger(seconds=60))
|
|
64
|
+
|
|
42
65
|
使用示例:
|
|
43
66
|
from apscheduler.triggers.cron import CronTrigger
|
|
44
67
|
from apscheduler.triggers.interval import IntervalTrigger
|
|
@@ -57,11 +80,16 @@ class SchedulerManager:
|
|
|
57
80
|
timezone="Asia/Shanghai",
|
|
58
81
|
)
|
|
59
82
|
|
|
60
|
-
#
|
|
61
|
-
@scheduler.scheduled_job(
|
|
83
|
+
# 字符串模式注册任务
|
|
84
|
+
@scheduler.scheduled_job("interval", seconds=60)
|
|
62
85
|
async def my_task():
|
|
63
86
|
...
|
|
64
87
|
|
|
88
|
+
# 原生对象模式
|
|
89
|
+
@scheduler.scheduled_job(CronTrigger.from_crontab("0 * * * *"))
|
|
90
|
+
async def hourly_task():
|
|
91
|
+
...
|
|
92
|
+
|
|
65
93
|
# 启动调度器
|
|
66
94
|
scheduler.start()
|
|
67
95
|
"""
|
|
@@ -200,46 +228,88 @@ class SchedulerManager:
|
|
|
200
228
|
raise RuntimeError("调度器未初始化,请先调用 initialize()")
|
|
201
229
|
return self._scheduler
|
|
202
230
|
|
|
231
|
+
def _build_trigger(self, trigger: TriggerType | BaseTrigger, **trigger_kwargs: Any) -> BaseTrigger:
|
|
232
|
+
"""构建触发器对象。
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
trigger: 触发器类型字符串("cron"/"interval")或原生触发器对象
|
|
236
|
+
**trigger_kwargs: 触发器参数(仅字符串模式时有效)
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
APScheduler 触发器对象
|
|
240
|
+
"""
|
|
241
|
+
# 如果已经是触发器对象,直接返回
|
|
242
|
+
if isinstance(trigger, BaseTrigger):
|
|
243
|
+
return trigger
|
|
244
|
+
|
|
245
|
+
# 字符串模式,构建触发器
|
|
246
|
+
if trigger == "cron":
|
|
247
|
+
return CronTrigger(**trigger_kwargs)
|
|
248
|
+
elif trigger == "interval":
|
|
249
|
+
return IntervalTrigger(**trigger_kwargs)
|
|
250
|
+
else:
|
|
251
|
+
raise ValueError(f"不支持的触发器类型: {trigger},支持 'cron' 或 'interval'")
|
|
252
|
+
|
|
203
253
|
def add_job(
|
|
204
254
|
self,
|
|
205
255
|
func: Callable,
|
|
206
|
-
trigger:
|
|
256
|
+
trigger: TriggerType | BaseTrigger,
|
|
207
257
|
*,
|
|
208
258
|
id: str | None = None,
|
|
209
259
|
**kwargs: Any,
|
|
210
260
|
) -> None:
|
|
211
261
|
"""添加任务。
|
|
212
262
|
|
|
213
|
-
|
|
263
|
+
支持两种触发器语法:
|
|
264
|
+
|
|
265
|
+
1. 字符串模式:trigger 为 "cron" 或 "interval",触发器参数通过 kwargs 传递
|
|
266
|
+
2. 原生对象模式:trigger 为 APScheduler 触发器对象
|
|
214
267
|
|
|
215
268
|
Args:
|
|
216
269
|
func: 任务函数
|
|
217
|
-
trigger:
|
|
218
|
-
-
|
|
219
|
-
- CronTrigger(
|
|
220
|
-
- CronTrigger.from_crontab("0 * * * *")
|
|
270
|
+
trigger: 触发器类型或触发器对象
|
|
271
|
+
- 字符串: "cron" 或 "interval"
|
|
272
|
+
- 对象: CronTrigger(...) 或 IntervalTrigger(...)
|
|
221
273
|
id: 任务ID(可选,默认使用函数完整路径)
|
|
222
|
-
**kwargs:
|
|
274
|
+
**kwargs: 触发器参数(字符串模式)或其他 APScheduler add_job 参数(对象模式)
|
|
223
275
|
|
|
224
276
|
示例:
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
# 每小时执行
|
|
229
|
-
scheduler.add_job(my_task, CronTrigger(hour="*"))
|
|
277
|
+
# === 字符串模式 ===
|
|
278
|
+
# 每小时整点执行
|
|
279
|
+
scheduler.add_job(my_task, "cron", hour="*", minute=0)
|
|
230
280
|
|
|
231
281
|
# 每 30 分钟执行
|
|
232
|
-
scheduler.add_job(my_task,
|
|
282
|
+
scheduler.add_job(my_task, "interval", minutes=30)
|
|
233
283
|
|
|
234
284
|
# 每天凌晨 2 点执行
|
|
235
|
-
scheduler.add_job(my_task,
|
|
285
|
+
scheduler.add_job(my_task, "cron", hour=2, minute=0)
|
|
286
|
+
|
|
287
|
+
# 每周一 9:00 执行
|
|
288
|
+
scheduler.add_job(my_task, "cron", day_of_week="mon", hour=9, minute=0)
|
|
289
|
+
|
|
290
|
+
# === 原生对象模式 ===
|
|
291
|
+
from apscheduler.triggers.cron import CronTrigger
|
|
292
|
+
from apscheduler.triggers.interval import IntervalTrigger
|
|
236
293
|
|
|
237
294
|
# 使用 crontab 表达式
|
|
238
295
|
scheduler.add_job(my_task, CronTrigger.from_crontab("0 2 * * *"))
|
|
296
|
+
|
|
297
|
+
# 原生触发器对象
|
|
298
|
+
scheduler.add_job(my_task, IntervalTrigger(seconds=60))
|
|
239
299
|
"""
|
|
240
300
|
if not self._initialized:
|
|
241
301
|
raise RuntimeError("调度器未初始化")
|
|
242
302
|
|
|
303
|
+
# 分离触发器参数和其他 add_job 参数
|
|
304
|
+
if isinstance(trigger, str):
|
|
305
|
+
# 字符串模式:需要从 kwargs 中分离触发器参数
|
|
306
|
+
trigger_params, job_params = self._separate_trigger_params(trigger, kwargs)
|
|
307
|
+
trigger_obj = self._build_trigger(trigger, **trigger_params)
|
|
308
|
+
else:
|
|
309
|
+
# 对象模式:kwargs 全部是 add_job 参数
|
|
310
|
+
trigger_obj = trigger
|
|
311
|
+
job_params = kwargs
|
|
312
|
+
|
|
243
313
|
# 包装任务函数,自动设置日志上下文
|
|
244
314
|
wrapped_func = self._wrap_with_context(func)
|
|
245
315
|
|
|
@@ -247,12 +317,52 @@ class SchedulerManager:
|
|
|
247
317
|
job_id = id or f"{func.__module__}.{func.__name__}"
|
|
248
318
|
self._scheduler.add_job(
|
|
249
319
|
func=wrapped_func,
|
|
250
|
-
trigger=
|
|
320
|
+
trigger=trigger_obj,
|
|
251
321
|
id=job_id,
|
|
252
|
-
**
|
|
322
|
+
**job_params,
|
|
253
323
|
)
|
|
254
324
|
|
|
255
|
-
logger.info(f"任务已注册: {job_id} | 触发器: {type(
|
|
325
|
+
logger.info(f"任务已注册: {job_id} | 触发器: {type(trigger_obj).__name__}")
|
|
326
|
+
|
|
327
|
+
def _separate_trigger_params(
|
|
328
|
+
self,
|
|
329
|
+
trigger_type: str,
|
|
330
|
+
kwargs: dict[str, Any]
|
|
331
|
+
) -> tuple[dict[str, Any], dict[str, Any]]:
|
|
332
|
+
"""分离触发器参数和 add_job 参数。
|
|
333
|
+
|
|
334
|
+
Args:
|
|
335
|
+
trigger_type: 触发器类型
|
|
336
|
+
kwargs: 混合参数
|
|
337
|
+
|
|
338
|
+
Returns:
|
|
339
|
+
(trigger_params, job_params) 元组
|
|
340
|
+
"""
|
|
341
|
+
# CronTrigger 支持的参数
|
|
342
|
+
cron_params = {
|
|
343
|
+
"year", "month", "day", "week", "day_of_week",
|
|
344
|
+
"hour", "minute", "second", "start_date", "end_date",
|
|
345
|
+
"timezone", "jitter"
|
|
346
|
+
}
|
|
347
|
+
# IntervalTrigger 支持的参数
|
|
348
|
+
interval_params = {
|
|
349
|
+
"weeks", "days", "hours", "minutes", "seconds",
|
|
350
|
+
"start_date", "end_date", "timezone", "jitter"
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
# 根据触发器类型选择参数集
|
|
354
|
+
trigger_param_names = cron_params if trigger_type == "cron" else interval_params
|
|
355
|
+
|
|
356
|
+
trigger_params: dict[str, Any] = {}
|
|
357
|
+
job_params: dict[str, Any] = {}
|
|
358
|
+
|
|
359
|
+
for key, value in kwargs.items():
|
|
360
|
+
if key in trigger_param_names:
|
|
361
|
+
trigger_params[key] = value
|
|
362
|
+
else:
|
|
363
|
+
job_params[key] = value
|
|
364
|
+
|
|
365
|
+
return trigger_params, job_params
|
|
256
366
|
|
|
257
367
|
def _wrap_with_context(self, func: Callable) -> Callable:
|
|
258
368
|
"""包装任务函数,自动设置 scheduler 日志上下文。"""
|
|
@@ -339,19 +449,35 @@ class SchedulerManager:
|
|
|
339
449
|
def reschedule_job(
|
|
340
450
|
self,
|
|
341
451
|
job_id: str,
|
|
342
|
-
trigger:
|
|
452
|
+
trigger: TriggerType | BaseTrigger,
|
|
453
|
+
**trigger_kwargs: Any,
|
|
343
454
|
) -> None:
|
|
344
455
|
"""重新调度任务。
|
|
345
456
|
|
|
457
|
+
支持两种触发器语法:
|
|
458
|
+
|
|
459
|
+
1. 字符串模式:trigger 为 "cron" 或 "interval",触发器参数通过 kwargs 传递
|
|
460
|
+
2. 原生对象模式:trigger 为 APScheduler 触发器对象
|
|
461
|
+
|
|
346
462
|
Args:
|
|
347
463
|
job_id: 任务ID
|
|
348
|
-
trigger:
|
|
464
|
+
trigger: 触发器类型或触发器对象
|
|
465
|
+
**trigger_kwargs: 触发器参数(仅字符串模式时有效)
|
|
466
|
+
|
|
467
|
+
示例:
|
|
468
|
+
# 字符串模式
|
|
469
|
+
scheduler.reschedule_job("my_job", "cron", hour="*/2")
|
|
470
|
+
scheduler.reschedule_job("my_job", "interval", minutes=15)
|
|
471
|
+
|
|
472
|
+
# 原生对象模式
|
|
473
|
+
scheduler.reschedule_job("my_job", CronTrigger(hour="*/2"))
|
|
349
474
|
"""
|
|
350
475
|
if not self._scheduler:
|
|
351
476
|
raise RuntimeError("调度器未初始化")
|
|
352
477
|
|
|
353
|
-
self.
|
|
354
|
-
|
|
478
|
+
trigger_obj = self._build_trigger(trigger, **trigger_kwargs)
|
|
479
|
+
self._scheduler.reschedule_job(job_id, trigger=trigger_obj)
|
|
480
|
+
logger.info(f"任务已重新调度: {job_id} | 触发器: {type(trigger_obj).__name__}")
|
|
355
481
|
|
|
356
482
|
def pause_job(self, job_id: str) -> None:
|
|
357
483
|
"""暂停单个任务。
|
|
@@ -414,35 +540,52 @@ class SchedulerManager:
|
|
|
414
540
|
|
|
415
541
|
def scheduled_job(
|
|
416
542
|
self,
|
|
417
|
-
trigger:
|
|
543
|
+
trigger: TriggerType | BaseTrigger,
|
|
418
544
|
*,
|
|
419
545
|
id: str | None = None,
|
|
420
546
|
**kwargs: Any,
|
|
421
547
|
) -> Callable[[Callable], Callable]:
|
|
422
548
|
"""任务注册装饰器。
|
|
423
549
|
|
|
550
|
+
支持两种触发器语法:
|
|
551
|
+
|
|
552
|
+
1. 字符串模式(推荐,简洁):
|
|
553
|
+
@scheduler.scheduled_job("cron", hour="*", minute=0)
|
|
554
|
+
@scheduler.scheduled_job("interval", seconds=60)
|
|
555
|
+
|
|
556
|
+
2. 原生对象模式(完整功能):
|
|
557
|
+
@scheduler.scheduled_job(CronTrigger(hour="*"))
|
|
558
|
+
@scheduler.scheduled_job(IntervalTrigger(seconds=60))
|
|
559
|
+
|
|
424
560
|
使用示例:
|
|
425
|
-
from apscheduler.triggers.cron import CronTrigger
|
|
426
|
-
from apscheduler.triggers.interval import IntervalTrigger
|
|
427
|
-
|
|
428
561
|
scheduler = SchedulerManager.get_instance()
|
|
429
562
|
|
|
430
|
-
|
|
563
|
+
# === 字符串模式 ===
|
|
564
|
+
@scheduler.scheduled_job("interval", seconds=60)
|
|
431
565
|
async def my_task():
|
|
432
|
-
print("
|
|
566
|
+
print("每分钟执行")
|
|
433
567
|
|
|
434
|
-
@scheduler.scheduled_job(
|
|
568
|
+
@scheduler.scheduled_job("cron", hour="*", minute=0)
|
|
435
569
|
async def hourly_task():
|
|
436
|
-
print("
|
|
570
|
+
print("每小时整点执行")
|
|
571
|
+
|
|
572
|
+
@scheduler.scheduled_job("cron", day_of_week="mon-fri", hour=9)
|
|
573
|
+
async def workday_task():
|
|
574
|
+
print("工作日 9 点执行")
|
|
575
|
+
|
|
576
|
+
# === 原生对象模式 ===
|
|
577
|
+
from apscheduler.triggers.cron import CronTrigger
|
|
437
578
|
|
|
438
579
|
@scheduler.scheduled_job(CronTrigger.from_crontab("0 0 * * *"))
|
|
439
580
|
async def daily_task():
|
|
440
|
-
print("
|
|
581
|
+
print("每天 0 点执行")
|
|
441
582
|
|
|
442
583
|
Args:
|
|
443
|
-
trigger:
|
|
444
|
-
|
|
445
|
-
|
|
584
|
+
trigger: 触发器类型或触发器对象
|
|
585
|
+
- 字符串: "cron" 或 "interval"
|
|
586
|
+
- 对象: CronTrigger(...) 或 IntervalTrigger(...)
|
|
587
|
+
id: 任务ID(可选,默认使用函数完整路径)
|
|
588
|
+
**kwargs: 触发器参数(字符串模式)或其他 APScheduler add_job 参数
|
|
446
589
|
|
|
447
590
|
Returns:
|
|
448
591
|
装饰器函数
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
"""定时任务模块(Scheduler)。
|
|
2
|
-
|
|
3
|
-
在此文件中定义定时任务,使用 @scheduler.scheduled_job() 装饰器。
|
|
4
|
-
|
|
5
|
-
框架会自动发现并加载本模块,无需在 main.py 中手动导入。
|
|
6
|
-
也可通过 SCHEDULER_SCHEDULE_MODULES 环境变量指定自定义模块。
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
# from apscheduler.triggers.cron import CronTrigger
|
|
10
|
-
# from apscheduler.triggers.interval import IntervalTrigger
|
|
11
|
-
#
|
|
12
|
-
# from aury.boot.common.logging import logger
|
|
13
|
-
# from aury.boot.infrastructure.scheduler import SchedulerManager
|
|
14
|
-
#
|
|
15
|
-
# scheduler = SchedulerManager.get_instance()
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# @scheduler.scheduled_job(IntervalTrigger(seconds=60))
|
|
19
|
-
# async def example_job():
|
|
20
|
-
# """示例定时任务,每 60 秒执行一次。"""
|
|
21
|
-
# logger.info("定时任务执行中...")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|