aury-boot 0.0.37__tar.gz → 0.0.38__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.37 → aury_boot-0.0.38}/PKG-INFO +1 -1
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/_version.py +2 -2
- aury_boot-0.0.38/aury/boot/infrastructure/cache/backends.py +14 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/cache/base.py +38 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/cache/manager.py +151 -1
- aury_boot-0.0.37/aury/boot/infrastructure/cache/backends.py → aury_boot-0.0.38/aury/boot/infrastructure/cache/memory.py +78 -204
- aury_boot-0.0.38/aury/boot/infrastructure/cache/redis.py +259 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/mq/backends/redis.py +1 -1
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/mq/backends/redis_stream.py +1 -1
- {aury_boot-0.0.37 → aury_boot-0.0.38}/.gitignore +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/README.md +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/adapter/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/adapter/base.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/adapter/config.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/adapter/decorators.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/adapter/exceptions.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/adapter/http.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/app/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/app/base.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/app/components.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/app/middlewares.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/app/startup.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/config/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/config/multi_instance.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/config/settings.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/constants/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/constants/components.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/constants/scheduler.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/constants/service.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/errors/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/errors/chain.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/errors/codes.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/errors/exceptions.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/errors/handlers.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/errors/response.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/interfaces/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/interfaces/egress.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/interfaces/ingress.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/middleware/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/middleware/logging.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/migrations/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/migrations/manager.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/migrations/setup.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/rpc/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/rpc/base.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/rpc/client.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/rpc/discovery.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/scheduler/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/scheduler/runner.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/application/server/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/add.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/app.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/config.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/docker.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/docs.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/generate.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/init.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/migrate/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/migrate/app.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/migrate/commands.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/pkg.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/scheduler.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/server/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/server/app.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/generate/api.py.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/generate/model.py.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/generate/repository.py.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/generate/schema.py.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/generate/service.py.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/AGENTS.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/README.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/admin_console_init.py.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/alert_rules.example.yaml.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/00-overview.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/01-model.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/02-repository.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/03-service.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/04-schema.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/05-api.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/06-exception.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/07-cache.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/08-scheduler.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/09-tasks.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/10-storage.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/11-logging.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/12-admin.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/13-channel.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/14-mq.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/15-events.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/16-adapter.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/17-alerting.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/aury_docs/99-cli.md.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/config.py.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/conftest.py.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/env_templates/_header.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/env_templates/admin.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/env_templates/cache.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/env_templates/database.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/env_templates/log.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/env_templates/messaging.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/env_templates/monitoring.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/env_templates/rpc.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/env_templates/scheduler.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/env_templates/service.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/env_templates/storage.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/env_templates/third_party.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/gitignore.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/main.py.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/modules/api.py.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/modules/exceptions.py.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/modules/schedules.py.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/templates/project/modules/tasks.py.tpl +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/commands/worker.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/common/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/common/exceptions/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/common/i18n/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/common/i18n/translator.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/common/logging/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/common/logging/context.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/common/logging/decorators.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/common/logging/format.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/common/logging/setup.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/contrib/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/contrib/admin_console/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/contrib/admin_console/auth.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/contrib/admin_console/discovery.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/contrib/admin_console/install.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/contrib/admin_console/utils.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/domain/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/domain/exceptions/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/domain/models/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/domain/models/base.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/domain/models/mixins.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/domain/models/models.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/domain/pagination/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/domain/repository/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/domain/repository/impl.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/domain/repository/interceptors.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/domain/repository/interface.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/domain/repository/query_builder.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/domain/service/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/domain/service/base.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/domain/transaction/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/cache/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/cache/exceptions.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/cache/factory.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/channel/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/channel/backends/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/channel/backends/broadcaster.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/channel/base.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/channel/manager.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/clients/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/clients/rabbitmq/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/clients/rabbitmq/config.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/clients/rabbitmq/manager.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/clients/redis/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/clients/redis/config.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/clients/redis/manager.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/database/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/database/config.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/database/exceptions.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/database/manager.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/database/query_tools/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/database/strategies/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/di/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/di/container.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/events/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/events/backends/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/events/backends/broadcaster.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/events/backends/rabbitmq.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/events/base.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/events/manager.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/events/middleware.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/alerting/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/alerting/aggregator.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/alerting/events.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/alerting/manager.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/alerting/notifiers/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/alerting/notifiers/base.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/alerting/notifiers/feishu.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/alerting/notifiers/webhook.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/alerting/rules.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/health/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/tracing/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/tracing/context.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/tracing/logging.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/tracing/processor.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/tracing/provider.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/monitoring/tracing/tracing.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/mq/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/mq/backends/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/mq/backends/rabbitmq.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/mq/base.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/mq/manager.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/scheduler/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/scheduler/exceptions.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/scheduler/manager.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/storage/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/storage/base.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/storage/exceptions.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/storage/factory.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/tasks/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/tasks/config.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/tasks/constants.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/tasks/exceptions.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/infrastructure/tasks/manager.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/testing/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/testing/base.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/testing/client.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/testing/factory.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/toolkit/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/aury/boot/toolkit/http/__init__.py +0 -0
- {aury_boot-0.0.37 → aury_boot-0.0.38}/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.38'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 0, 38)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -71,6 +71,44 @@ class ICache(ABC):
|
|
|
71
71
|
async def close(self) -> None:
|
|
72
72
|
"""关闭连接。"""
|
|
73
73
|
pass
|
|
74
|
+
|
|
75
|
+
# ==================== 分布式锁 ====================
|
|
76
|
+
|
|
77
|
+
@abstractmethod
|
|
78
|
+
async def acquire_lock(
|
|
79
|
+
self,
|
|
80
|
+
key: str,
|
|
81
|
+
token: str,
|
|
82
|
+
timeout: int,
|
|
83
|
+
blocking: bool,
|
|
84
|
+
blocking_timeout: float | None,
|
|
85
|
+
) -> bool:
|
|
86
|
+
"""获取分布式锁。
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
key: 锁的键名(已加 lock: 前缀)
|
|
90
|
+
token: 锁的 token
|
|
91
|
+
timeout: 锁的超时时间(秒)
|
|
92
|
+
blocking: 是否阻塞等待
|
|
93
|
+
blocking_timeout: 阻塞等待的最大时间(秒)
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
bool: 是否获取成功
|
|
97
|
+
"""
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
@abstractmethod
|
|
101
|
+
async def release_lock(self, key: str, token: str) -> bool:
|
|
102
|
+
"""释放分布式锁。
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
key: 锁的键名(已加 lock: 前缀)
|
|
106
|
+
token: 获取锁时的 token
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
bool: 是否成功释放
|
|
110
|
+
"""
|
|
111
|
+
pass
|
|
74
112
|
|
|
75
113
|
|
|
76
114
|
__all__ = [
|
|
@@ -5,11 +5,15 @@
|
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
|
+
import asyncio
|
|
8
9
|
from collections.abc import Callable
|
|
10
|
+
from contextlib import asynccontextmanager
|
|
9
11
|
from datetime import timedelta
|
|
10
12
|
from functools import wraps
|
|
11
13
|
import hashlib
|
|
12
|
-
|
|
14
|
+
import time
|
|
15
|
+
from typing import Any, AsyncIterator, TypeVar
|
|
16
|
+
import uuid
|
|
13
17
|
|
|
14
18
|
from aury.boot.common.logging import logger
|
|
15
19
|
|
|
@@ -328,6 +332,152 @@ class CacheManager:
|
|
|
328
332
|
self._backend = None
|
|
329
333
|
logger.info("缓存管理器已清理")
|
|
330
334
|
|
|
335
|
+
# ==================== 分布式锁 ====================
|
|
336
|
+
|
|
337
|
+
async def acquire_lock(
|
|
338
|
+
self,
|
|
339
|
+
key: str,
|
|
340
|
+
*,
|
|
341
|
+
timeout: int = 30,
|
|
342
|
+
blocking: bool = True,
|
|
343
|
+
blocking_timeout: float | None = None,
|
|
344
|
+
) -> str | None:
|
|
345
|
+
"""获取分布式锁。
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
key: 锁的键名
|
|
349
|
+
timeout: 锁的超时时间(秒),防止死锁
|
|
350
|
+
blocking: 是否阻塞等待
|
|
351
|
+
blocking_timeout: 阻塞等待的最大时间(秒)
|
|
352
|
+
|
|
353
|
+
Returns:
|
|
354
|
+
str | None: 锁的 token(用于释放),获取失败返回 None
|
|
355
|
+
"""
|
|
356
|
+
lock_key = f"lock:{key}"
|
|
357
|
+
token = str(uuid.uuid4())
|
|
358
|
+
|
|
359
|
+
acquired = await self.backend.acquire_lock(
|
|
360
|
+
lock_key, token, timeout, blocking, blocking_timeout
|
|
361
|
+
)
|
|
362
|
+
return token if acquired else None
|
|
363
|
+
|
|
364
|
+
async def release_lock(self, key: str, token: str) -> bool:
|
|
365
|
+
"""释放分布式锁。
|
|
366
|
+
|
|
367
|
+
Args:
|
|
368
|
+
key: 锁的键名
|
|
369
|
+
token: acquire_lock 返回的 token
|
|
370
|
+
|
|
371
|
+
Returns:
|
|
372
|
+
bool: 是否成功释放
|
|
373
|
+
"""
|
|
374
|
+
lock_key = f"lock:{key}"
|
|
375
|
+
return await self.backend.release_lock(lock_key, token)
|
|
376
|
+
|
|
377
|
+
@asynccontextmanager
|
|
378
|
+
async def lock(
|
|
379
|
+
self,
|
|
380
|
+
key: str,
|
|
381
|
+
*,
|
|
382
|
+
timeout: int = 30,
|
|
383
|
+
blocking: bool = True,
|
|
384
|
+
blocking_timeout: float | None = None,
|
|
385
|
+
) -> AsyncIterator[bool]:
|
|
386
|
+
"""分布式锁上下文管理器。
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
key: 锁的键名
|
|
390
|
+
timeout: 锁的超时时间(秒)
|
|
391
|
+
blocking: 是否阻塞等待
|
|
392
|
+
blocking_timeout: 阻塞等待的最大时间(秒)
|
|
393
|
+
|
|
394
|
+
Yields:
|
|
395
|
+
bool: 是否成功获取锁
|
|
396
|
+
|
|
397
|
+
示例:
|
|
398
|
+
async with cache.lock("my_resource") as acquired:
|
|
399
|
+
if acquired:
|
|
400
|
+
# 执行需要互斥的操作
|
|
401
|
+
pass
|
|
402
|
+
"""
|
|
403
|
+
token = await self.acquire_lock(
|
|
404
|
+
key,
|
|
405
|
+
timeout=timeout,
|
|
406
|
+
blocking=blocking,
|
|
407
|
+
blocking_timeout=blocking_timeout,
|
|
408
|
+
)
|
|
409
|
+
try:
|
|
410
|
+
yield token is not None
|
|
411
|
+
finally:
|
|
412
|
+
if token:
|
|
413
|
+
await self.release_lock(key, token)
|
|
414
|
+
|
|
415
|
+
@asynccontextmanager
|
|
416
|
+
async def semaphore(
|
|
417
|
+
self,
|
|
418
|
+
key: str,
|
|
419
|
+
max_concurrency: int,
|
|
420
|
+
*,
|
|
421
|
+
timeout: int = 300,
|
|
422
|
+
blocking: bool = True,
|
|
423
|
+
blocking_timeout: float | None = None,
|
|
424
|
+
) -> AsyncIterator[bool]:
|
|
425
|
+
"""分布式信号量(限制并发数)。
|
|
426
|
+
|
|
427
|
+
Args:
|
|
428
|
+
key: 信号量的键名
|
|
429
|
+
max_concurrency: 最大并发数
|
|
430
|
+
timeout: 单个槽位的超时时间(秒)
|
|
431
|
+
blocking: 是否阻塞等待
|
|
432
|
+
blocking_timeout: 阻塞等待的最大时间(秒)
|
|
433
|
+
|
|
434
|
+
Yields:
|
|
435
|
+
bool: 是否成功获取槽位
|
|
436
|
+
|
|
437
|
+
示例:
|
|
438
|
+
async with cache.semaphore("pdf_ocr", max_concurrency=2) as acquired:
|
|
439
|
+
if acquired:
|
|
440
|
+
# 执行受并发限制的操作
|
|
441
|
+
pass
|
|
442
|
+
"""
|
|
443
|
+
slot_token: str | None = None
|
|
444
|
+
acquired_slot: int | None = None
|
|
445
|
+
start_time = time.monotonic()
|
|
446
|
+
|
|
447
|
+
try:
|
|
448
|
+
while True:
|
|
449
|
+
# 尝试获取任意一个槽位
|
|
450
|
+
for slot in range(max_concurrency):
|
|
451
|
+
slot_key = f"{key}:slot:{slot}"
|
|
452
|
+
token = await self.acquire_lock(
|
|
453
|
+
slot_key,
|
|
454
|
+
timeout=timeout,
|
|
455
|
+
blocking=False,
|
|
456
|
+
)
|
|
457
|
+
if token:
|
|
458
|
+
slot_token = token
|
|
459
|
+
acquired_slot = slot
|
|
460
|
+
yield True
|
|
461
|
+
return
|
|
462
|
+
|
|
463
|
+
if not blocking:
|
|
464
|
+
yield False
|
|
465
|
+
return
|
|
466
|
+
|
|
467
|
+
# 检查是否超时
|
|
468
|
+
if blocking_timeout is not None:
|
|
469
|
+
elapsed = time.monotonic() - start_time
|
|
470
|
+
if elapsed >= blocking_timeout:
|
|
471
|
+
yield False
|
|
472
|
+
return
|
|
473
|
+
|
|
474
|
+
# 等待后重试
|
|
475
|
+
await asyncio.sleep(0.1)
|
|
476
|
+
finally:
|
|
477
|
+
if slot_token and acquired_slot is not None:
|
|
478
|
+
slot_key = f"{key}:slot:{acquired_slot}"
|
|
479
|
+
await self.release_lock(slot_key, slot_token)
|
|
480
|
+
|
|
331
481
|
def __repr__(self) -> str:
|
|
332
482
|
"""字符串表示。"""
|
|
333
483
|
backend_name = self.backend_type if self._backend else "未初始化"
|
|
@@ -1,208 +1,18 @@
|
|
|
1
|
-
"""缓存后端实现。
|
|
2
|
-
|
|
3
|
-
提供 Redis、Memory、Memcached 等缓存后端的实现。
|
|
4
|
-
"""
|
|
1
|
+
"""内存和 Memcached 缓存后端实现。"""
|
|
5
2
|
|
|
6
3
|
from __future__ import annotations
|
|
7
4
|
|
|
8
5
|
import asyncio
|
|
9
|
-
|
|
10
|
-
from datetime import timedelta
|
|
6
|
+
import fnmatch
|
|
11
7
|
import json
|
|
12
|
-
import
|
|
13
|
-
from
|
|
14
|
-
|
|
15
|
-
from redis.asyncio import Redis
|
|
8
|
+
import time
|
|
9
|
+
from datetime import timedelta
|
|
10
|
+
from typing import Any
|
|
16
11
|
|
|
17
12
|
from aury.boot.common.logging import logger
|
|
18
13
|
|
|
19
14
|
from .base import ICache
|
|
20
15
|
|
|
21
|
-
if TYPE_CHECKING:
|
|
22
|
-
from aury.boot.infrastructure.clients.redis import RedisClient
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class RedisCache(ICache):
|
|
26
|
-
"""Redis缓存实现。
|
|
27
|
-
|
|
28
|
-
支持两种初始化方式:
|
|
29
|
-
1. 传入 URL 自行创建连接
|
|
30
|
-
2. 传入 RedisClient 实例(推荐)
|
|
31
|
-
"""
|
|
32
|
-
|
|
33
|
-
def __init__(
|
|
34
|
-
self,
|
|
35
|
-
url: str | None = None,
|
|
36
|
-
*,
|
|
37
|
-
redis_client: RedisClient | None = None,
|
|
38
|
-
serializer: str = "json",
|
|
39
|
-
):
|
|
40
|
-
"""初始化Redis缓存。
|
|
41
|
-
|
|
42
|
-
Args:
|
|
43
|
-
url: Redis连接URL
|
|
44
|
-
redis_client: RedisClient 实例(推荐)
|
|
45
|
-
serializer: 序列化方式(json/pickle)
|
|
46
|
-
"""
|
|
47
|
-
self._url = url
|
|
48
|
-
self._redis_client = redis_client
|
|
49
|
-
self._serializer = serializer
|
|
50
|
-
self._redis: Redis | None = None
|
|
51
|
-
self._owns_connection = False # 是否自己拥有连接(需要自己关闭)
|
|
52
|
-
|
|
53
|
-
async def initialize(self) -> None:
|
|
54
|
-
"""初始化连接。"""
|
|
55
|
-
# 优先使用 RedisClient
|
|
56
|
-
if self._redis_client is not None:
|
|
57
|
-
self._redis = self._redis_client.connection
|
|
58
|
-
self._owns_connection = False
|
|
59
|
-
logger.info("Redis缓存初始化成功(使用 RedisClient)")
|
|
60
|
-
return
|
|
61
|
-
|
|
62
|
-
# 使用 URL 创建连接
|
|
63
|
-
if self._url:
|
|
64
|
-
try:
|
|
65
|
-
self._redis = Redis.from_url(
|
|
66
|
-
self._url,
|
|
67
|
-
encoding="utf-8",
|
|
68
|
-
decode_responses=False,
|
|
69
|
-
socket_connect_timeout=5,
|
|
70
|
-
socket_timeout=5,
|
|
71
|
-
)
|
|
72
|
-
await self._redis.ping()
|
|
73
|
-
self._owns_connection = True
|
|
74
|
-
logger.info("Redis缓存初始化成功")
|
|
75
|
-
except Exception as exc:
|
|
76
|
-
logger.error(f"Redis连接失败: {exc}")
|
|
77
|
-
raise
|
|
78
|
-
else:
|
|
79
|
-
raise ValueError("Redis缓存需要提供 url 或 redis_client 参数")
|
|
80
|
-
|
|
81
|
-
async def get(self, key: str, default: Any = None) -> Any:
|
|
82
|
-
"""获取缓存。"""
|
|
83
|
-
if not self._redis:
|
|
84
|
-
return default
|
|
85
|
-
|
|
86
|
-
try:
|
|
87
|
-
data = await self._redis.get(key)
|
|
88
|
-
if data is None:
|
|
89
|
-
return default
|
|
90
|
-
|
|
91
|
-
# 使用函数式编程处理序列化器
|
|
92
|
-
deserializers: dict[str, Callable[[bytes], Any]] = {
|
|
93
|
-
"json": lambda d: json.loads(d.decode()),
|
|
94
|
-
"pickle": pickle.loads,
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
deserializer = deserializers.get(self._serializer)
|
|
98
|
-
if deserializer:
|
|
99
|
-
return deserializer(data)
|
|
100
|
-
return data.decode()
|
|
101
|
-
except Exception as exc:
|
|
102
|
-
logger.error(f"Redis获取失败: {key}, {exc}")
|
|
103
|
-
return default
|
|
104
|
-
|
|
105
|
-
async def set(
|
|
106
|
-
self,
|
|
107
|
-
key: str,
|
|
108
|
-
value: Any,
|
|
109
|
-
expire: int | timedelta | None = None,
|
|
110
|
-
) -> bool:
|
|
111
|
-
"""设置缓存。"""
|
|
112
|
-
if not self._redis:
|
|
113
|
-
return False
|
|
114
|
-
|
|
115
|
-
try:
|
|
116
|
-
# 使用函数式编程处理序列化器
|
|
117
|
-
serializers: dict[str, Callable[[Any], bytes]] = {
|
|
118
|
-
"json": lambda v: json.dumps(v).encode(),
|
|
119
|
-
"pickle": pickle.dumps,
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
serializer = serializers.get(self._serializer)
|
|
123
|
-
if serializer:
|
|
124
|
-
data = serializer(value)
|
|
125
|
-
else:
|
|
126
|
-
data = str(value).encode()
|
|
127
|
-
|
|
128
|
-
# 转换过期时间
|
|
129
|
-
if isinstance(expire, timedelta):
|
|
130
|
-
expire = int(expire.total_seconds())
|
|
131
|
-
|
|
132
|
-
await self._redis.set(key, data, ex=expire)
|
|
133
|
-
return True
|
|
134
|
-
except Exception as exc:
|
|
135
|
-
logger.error(f"Redis设置失败: {key}, {exc}")
|
|
136
|
-
return False
|
|
137
|
-
|
|
138
|
-
async def delete(self, *keys: str) -> int:
|
|
139
|
-
"""删除缓存。"""
|
|
140
|
-
if not self._redis or not keys:
|
|
141
|
-
return 0
|
|
142
|
-
|
|
143
|
-
try:
|
|
144
|
-
return await self._redis.delete(*keys)
|
|
145
|
-
except Exception as exc:
|
|
146
|
-
logger.error(f"Redis删除失败: {keys}, {exc}")
|
|
147
|
-
return 0
|
|
148
|
-
|
|
149
|
-
async def exists(self, *keys: str) -> int:
|
|
150
|
-
"""检查缓存是否存在。"""
|
|
151
|
-
if not self._redis or not keys:
|
|
152
|
-
return 0
|
|
153
|
-
|
|
154
|
-
try:
|
|
155
|
-
return await self._redis.exists(*keys)
|
|
156
|
-
except Exception as exc:
|
|
157
|
-
logger.error(f"Redis检查失败: {keys}, {exc}")
|
|
158
|
-
return 0
|
|
159
|
-
|
|
160
|
-
async def clear(self) -> None:
|
|
161
|
-
"""清空所有缓存。"""
|
|
162
|
-
if self._redis:
|
|
163
|
-
await self._redis.flushdb()
|
|
164
|
-
logger.info("Redis缓存已清空")
|
|
165
|
-
|
|
166
|
-
async def delete_pattern(self, pattern: str) -> int:
|
|
167
|
-
"""按模式删除缓存。
|
|
168
|
-
|
|
169
|
-
Args:
|
|
170
|
-
pattern: 通配符模式,如 "todo:*"
|
|
171
|
-
|
|
172
|
-
Returns:
|
|
173
|
-
int: 删除的键数量
|
|
174
|
-
"""
|
|
175
|
-
if not self._redis:
|
|
176
|
-
return 0
|
|
177
|
-
|
|
178
|
-
try:
|
|
179
|
-
# 使用 SCAN 遍历匹配的键(比 KEYS 更安全,不会阻塞)
|
|
180
|
-
count = 0
|
|
181
|
-
cursor = 0
|
|
182
|
-
while True:
|
|
183
|
-
cursor, keys = await self._redis.scan(cursor, match=pattern, count=100)
|
|
184
|
-
if keys:
|
|
185
|
-
count += await self._redis.delete(*keys)
|
|
186
|
-
if cursor == 0:
|
|
187
|
-
break
|
|
188
|
-
logger.debug(f"按模式删除缓存: {pattern}, 删除 {count} 个键")
|
|
189
|
-
return count
|
|
190
|
-
except Exception as exc:
|
|
191
|
-
logger.error(f"Redis模式删除失败: {pattern}, {exc}")
|
|
192
|
-
return 0
|
|
193
|
-
|
|
194
|
-
async def close(self) -> None:
|
|
195
|
-
"""关闭连接(仅当自己拥有连接时)。"""
|
|
196
|
-
if self._redis and self._owns_connection:
|
|
197
|
-
await self._redis.close()
|
|
198
|
-
logger.info("Redis连接已关闭")
|
|
199
|
-
self._redis = None
|
|
200
|
-
|
|
201
|
-
@property
|
|
202
|
-
def redis(self) -> Redis | None:
|
|
203
|
-
"""获取Redis客户端。"""
|
|
204
|
-
return self._redis
|
|
205
|
-
|
|
206
16
|
|
|
207
17
|
class MemoryCache(ICache):
|
|
208
18
|
"""内存缓存实现。"""
|
|
@@ -295,8 +105,6 @@ class MemoryCache(ICache):
|
|
|
295
105
|
Returns:
|
|
296
106
|
int: 删除的键数量
|
|
297
107
|
"""
|
|
298
|
-
import fnmatch
|
|
299
|
-
|
|
300
108
|
async with self._lock:
|
|
301
109
|
keys_to_delete = [
|
|
302
110
|
key for key in self._cache
|
|
@@ -314,6 +122,60 @@ class MemoryCache(ICache):
|
|
|
314
122
|
async def size(self) -> int:
|
|
315
123
|
"""获取缓存大小。"""
|
|
316
124
|
return len(self._cache)
|
|
125
|
+
|
|
126
|
+
# ==================== 内存锁 ====================
|
|
127
|
+
|
|
128
|
+
async def acquire_lock(
|
|
129
|
+
self,
|
|
130
|
+
key: str,
|
|
131
|
+
token: str,
|
|
132
|
+
timeout: int,
|
|
133
|
+
blocking: bool,
|
|
134
|
+
blocking_timeout: float | None,
|
|
135
|
+
) -> bool:
|
|
136
|
+
"""获取内存锁(单进程)。"""
|
|
137
|
+
start_time = time.monotonic()
|
|
138
|
+
|
|
139
|
+
while True:
|
|
140
|
+
async with self._lock:
|
|
141
|
+
# 检查锁是否存在
|
|
142
|
+
if key not in self._cache:
|
|
143
|
+
# 设置锁
|
|
144
|
+
expire_at = asyncio.get_event_loop().time() + timeout
|
|
145
|
+
self._cache[key] = (token, expire_at)
|
|
146
|
+
return True
|
|
147
|
+
|
|
148
|
+
# 检查锁是否过期
|
|
149
|
+
existing_token, expire_at = self._cache[key]
|
|
150
|
+
if expire_at is not None and asyncio.get_event_loop().time() > expire_at:
|
|
151
|
+
# 锁已过期,重新获取
|
|
152
|
+
new_expire_at = asyncio.get_event_loop().time() + timeout
|
|
153
|
+
self._cache[key] = (token, new_expire_at)
|
|
154
|
+
return True
|
|
155
|
+
|
|
156
|
+
if not blocking:
|
|
157
|
+
return False
|
|
158
|
+
|
|
159
|
+
# 检查是否超时
|
|
160
|
+
if blocking_timeout is not None:
|
|
161
|
+
elapsed = time.monotonic() - start_time
|
|
162
|
+
if elapsed >= blocking_timeout:
|
|
163
|
+
return False
|
|
164
|
+
|
|
165
|
+
# 短暂等待后重试
|
|
166
|
+
await asyncio.sleep(0.05)
|
|
167
|
+
|
|
168
|
+
async def release_lock(self, key: str, token: str) -> bool:
|
|
169
|
+
"""释放内存锁。"""
|
|
170
|
+
async with self._lock:
|
|
171
|
+
if key not in self._cache:
|
|
172
|
+
return False
|
|
173
|
+
|
|
174
|
+
existing_token, _ = self._cache[key]
|
|
175
|
+
if existing_token == token:
|
|
176
|
+
del self._cache[key]
|
|
177
|
+
return True
|
|
178
|
+
return False
|
|
317
179
|
|
|
318
180
|
|
|
319
181
|
class MemcachedCache(ICache):
|
|
@@ -323,7 +185,7 @@ class MemcachedCache(ICache):
|
|
|
323
185
|
"""初始化Memcached缓存。
|
|
324
186
|
|
|
325
187
|
Args:
|
|
326
|
-
servers: Memcached服务器列表,如 ["
|
|
188
|
+
servers: Memcached服务器列表,如 ["*********:11211"]
|
|
327
189
|
"""
|
|
328
190
|
self._servers = servers
|
|
329
191
|
self._client = None
|
|
@@ -422,11 +284,23 @@ class MemcachedCache(ICache):
|
|
|
422
284
|
if self._client:
|
|
423
285
|
self._client.close()
|
|
424
286
|
logger.info("Memcached连接已关闭")
|
|
287
|
+
|
|
288
|
+
# Memcached 不支持分布式锁
|
|
289
|
+
async def acquire_lock(
|
|
290
|
+
self,
|
|
291
|
+
key: str,
|
|
292
|
+
token: str,
|
|
293
|
+
timeout: int,
|
|
294
|
+
blocking: bool,
|
|
295
|
+
blocking_timeout: float | None,
|
|
296
|
+
) -> bool:
|
|
297
|
+
"""获取锁(Memcached 不支持)。"""
|
|
298
|
+
logger.warning("Memcached 不支持分布式锁,请使用 Redis 或 Memory 后端")
|
|
299
|
+
return False
|
|
300
|
+
|
|
301
|
+
async def release_lock(self, key: str, token: str) -> bool:
|
|
302
|
+
"""释放锁(Memcached 不支持)。"""
|
|
303
|
+
return False
|
|
425
304
|
|
|
426
305
|
|
|
427
|
-
__all__ = [
|
|
428
|
-
"MemcachedCache",
|
|
429
|
-
"MemoryCache",
|
|
430
|
-
"RedisCache",
|
|
431
|
-
]
|
|
432
|
-
|
|
306
|
+
__all__ = ["MemcachedCache", "MemoryCache"]
|