| Name | symphra-scheduler JSON |
| Version |
1.0.2
JSON |
| download |
| home_page | None |
| Summary | A high-performance async task scheduler with cron support, auto-discovery, retry mechanism, and configuration management |
| upload_time | 2025-10-26 12:07:47 |
| maintainer | None |
| docs_url | None |
| author | None |
| requires_python | >=3.11 |
| license | MIT |
| keywords |
async
asyncio
cron
queue
scheduler
task
timer
|
| VCS |
 |
| bugtrack_url |
|
| requirements |
No requirements were recorded.
|
| Travis-CI |
No Travis.
|
| coveralls test coverage |
|
# Symphra Scheduler
[](https://www.python.org/downloads/)
[](LICENSE)
高性能异步定时任务调度库,专为 Python 3.11+ 设计。
## 特性
- **高性能异步** - 基于 asyncio,支持高并发任务执行
- **秒级精度** - 支持秒级定时任务,基于 Cron 表达式
- **多种后端** - 支持内存、Redis、RabbitMQ、SQLite 作为队列后端
- **重试机制** - 内置智能重试,支持指数退避策略
- **简洁 API** - 装饰器模式,一行代码即可定义任务
- **自动发现** - 自动扫描目录或包,发现并注册任务
- **类型安全** - 完整的类型提示,IDE 友好
- **配置灵活** - 支持代码配置、文件配置(JSON/TOML/YAML)
- **后台运行** - 支持守护进程模式,优雅关闭
- **低内存占用** - 精心优化,适合长时间运行
- **零依赖启动** - 默认内存后端,无需外部服务
## 安装
### 基础安装(仅内存/SQLite后端)
```bash
pip install symphra_scheduler
```
### 安装 Redis 支持
```bash
pip install symphra-scheduler[redis]
# 或
pip install symphra-scheduler redis
```
### 安装 RabbitMQ 支持
```bash
pip install symphra-scheduler[rabbitmq]
# 或
pip install symphra-scheduler aio-pika
```
### 完整安装
```bash
pip install symphra-scheduler[all]
```
## 快速开始
### 基础用法
```python
import asyncio
from symphra_scheduler import Scheduler, cron, interval
# 创建调度器
scheduler = Scheduler()
# 使用装饰器定义任务
@cron("*/5 * * * * *") # 每5秒执行
async def task1():
print("每5秒执行一次")
@interval(30) # 每30秒执行
async def task2():
print("每30秒执行一次")
# 运行调度器
async def main():
await scheduler.start()
if __name__ == "__main__":
asyncio.run(main())
```
### 使用 Redis 后端
```python
from symphra_scheduler import Scheduler, SchedulerConfig, cron
from symphra_scheduler.backends import RedisBackend
# 配置 Redis 后端
backend = RedisBackend(url="redis://localhost:6379/0")
config = SchedulerConfig(max_workers=20)
scheduler = Scheduler(config=config, backend=backend)
@cron("0 0 * * *") # 每天零点执行
async def daily_cleanup():
print("执行每日清理任务")
await cleanup_old_data()
async def main():
await scheduler.start(daemon=True)
asyncio.run(main())
```
### 使用 SQLite 本地持久化
```python
from symphra_scheduler import Scheduler, interval
from symphra_scheduler.backends import SQLiteBackend
# SQLite 后端,任务持久化到本地文件
backend = SQLiteBackend(db_path="scheduler.db")
scheduler = Scheduler(backend=backend)
@interval(60)
async def sync_task():
print("同步数据...")
await sync_data()
asyncio.run(scheduler.start())
```
### 任务自动发现
适合模块化项目,自动扫描并注册任务:
```python
from symphra_scheduler import Scheduler
scheduler = Scheduler()
# 自动发现并注册目录下所有任务
# 项目结构:
# app/
# modules/
# user/task.py
# email/task.py
# report/task.py
tasks = scheduler.discover_tasks_from_directory("app/modules")
print(f"自动发现并注册了 {len(tasks)} 个任务")
# 使用自定义文件名模式
tasks = scheduler.discover_tasks_from_directory(
"app",
pattern="*_tasks.py",
exclude_patterns=["test_*.py"]
)
# 从包中发现
tasks = scheduler.discover_tasks_from_package("my_app.tasks")
asyncio.run(scheduler.start())
```
### 高级用法
```python
from datetime import datetime, timedelta
from symphra_scheduler import Scheduler, scheduled, RetryPolicy
scheduler = Scheduler()
# 自定义重试策略
@scheduled(
interval=10,
retry_policy=RetryPolicy(
max_attempts=5,
strategy="exponential",
wait_min=1.0,
wait_max=60.0,
),
timeout=30.0, # 30秒超时
max_instances=3, # 最多3个并发实例
tags=["critical", "data-sync"],
)
async def important_task():
"""重要任务,需要重试和超时控制"""
await process_critical_data()
# 一次性任务
from symphra_scheduler.decorators import once
@once(at=datetime(2025, 12, 31, 23, 59, 59))
async def new_year_celebration():
print("新年快乐!")
```
### 配置文件方式
**config.toml:**
```toml
max_workers = 20
queue_size = 5000
shutdown_timeout = 60.0
enable_logging = true
log_level = "INFO"
timezone = "Asia/Shanghai"
persistence_enabled = true
persistence_path = "scheduler_state.json"
```
**Python 代码:**
```python
from symphra_scheduler import Scheduler, SchedulerConfig
# 从配置文件加载
config = SchedulerConfig.from_file("config.toml")
scheduler = Scheduler(config=config)
```
## 后端对比
| 后端 | 适用场景 | 持久化 | 分布式 | 性能 | 依赖 |
|------|---------|--------|--------|------|------|
| **Memory** | 开发、测试、单机 | ✗ | ✗ | ⭐⭐⭐⭐⭐ | 无 |
| **SQLite** | 单机生产、需要持久化 | ✓ | ✗ | ⭐⭐⭐⭐ | 无 |
| **Redis** | 分布式、高性能 | ✓ | ✓ | ⭐⭐⭐⭐⭐ | Redis |
| **RabbitMQ** | 高可靠性、消息队列 | ✓ | ✓ | ⭐⭐⭐⭐ | RabbitMQ |
## Cron 表达式
Symphra Scheduler 支持标准 Cron 表达式,并扩展支持秒级精度:
```
秒 分 时 日 月 周
示例:
*/5 * * * * * - 每5秒
0 */10 * * * * - 每10分钟
0 0 9 * * * - 每天上午9点
0 0 0 1 * * - 每月1号零点
0 0 0 * * 1 - 每周一零点
*/30 * 9-17 * * 1-5 - 工作日9-17点每30秒
```
## 监控和统计
```python
# 获取调度器统计信息
stats = await scheduler.get_stats()
print(stats)
# {
# "running": true,
# "total_tasks": 5,
# "queue_size": 12,
# "active_workers": 10,
# "max_workers": 20,
# "backend": "RedisBackend",
# "tasks": [...]
# }
# 获取单个任务的指标
task = scheduler.get_task("task_name")
print(task.metrics)
# TaskMetrics(
# total_runs=100,
# successful_runs=95,
# failed_runs=5,
# average_execution_time=1.23
# )
```
## 架构设计
```
┌─────────────────────────────────────────┐
│ Scheduler (调度器) │
│ - 任务注册和管理 │
│ - 工作协程池 │
│ - 优雅关闭 │
└───────────┬─────────────────────────────┘
│
├─── 装饰器 API (@cron, @interval)
│
├─── 任务队列
│ └─── 后端抽象层
│ ├─── MemoryBackend
│ ├─── SQLiteBackend
│ ├─── RedisBackend
│ └─── RabbitMQBackend
│
└─── 任务执行
├─── 超时控制
├─── 重试机制 (tenacity)
├─── 并发控制
└─── 指标收集
```
## 为什么选择 Symphra Scheduler?
### vs Celery
- ✅ **更轻量** - 无需 Redis/RabbitMQ 即可运行
- ✅ **更简单** - 装饰器即用,无需额外配置
- ✅ **更快速** - 纯 asyncio,无进程开销
- ✅ **更现代** - Python 3.11+ 新特性,完整类型提示
### vs APScheduler
- ✅ **更高性能** - 原生异步,不是同步转异步
- ✅ **更好的可靠性** - 经过优化的内存管理
- ✅ **更灵活** - 可插拔后端,支持多种存储
- ✅ **更好的可观测性** - 内置指标和监控
## 开发
```bash
# 克隆仓库
git clone https://github.com/getaix/symphra-scheduler.git
cd symphra-scheduler
# 安装开发依赖
pip install -e ".[dev]"
# 运行测试
pytest tests/ -v --cov=symphra_scheduler --cov-report=html
# 代码检查
ruff check symphra_scheduler/
mypy symphra_scheduler/
# 格式化代码
black symphra_scheduler/
```
## 许可证
MIT License - 详见 [LICENSE](LICENSE) 文件
## 贡献
欢迎提交 Issue 和 Pull Request!
## 链接
- 📖 [完整文档](https://getaix.github.io/symphra-scheduler)
- 🐛 [问题反馈](https://github.com/getaix/symphra-scheduler/issues)
- 📦 [PyPI](https://pypi.org/project/symphra-scheduler/)
Raw data
{
"_id": null,
"home_page": null,
"name": "symphra-scheduler",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": "async, asyncio, cron, queue, scheduler, task, timer",
"author": null,
"author_email": "getaix <develop@getaix.tech>",
"download_url": "https://files.pythonhosted.org/packages/79/ba/b5c8a50655fe0c6c38419d62237e1eec57df5528ae082e44e568bc0a6283/symphra_scheduler-1.0.2.tar.gz",
"platform": null,
"description": "# Symphra Scheduler\n\n[](https://www.python.org/downloads/)\n[](LICENSE)\n\n\u9ad8\u6027\u80fd\u5f02\u6b65\u5b9a\u65f6\u4efb\u52a1\u8c03\u5ea6\u5e93,\u4e13\u4e3a Python 3.11+ \u8bbe\u8ba1\u3002\n\n## \u7279\u6027\n\n- **\u9ad8\u6027\u80fd\u5f02\u6b65** - \u57fa\u4e8e asyncio,\u652f\u6301\u9ad8\u5e76\u53d1\u4efb\u52a1\u6267\u884c\n- **\u79d2\u7ea7\u7cbe\u5ea6** - \u652f\u6301\u79d2\u7ea7\u5b9a\u65f6\u4efb\u52a1,\u57fa\u4e8e Cron \u8868\u8fbe\u5f0f\n- **\u591a\u79cd\u540e\u7aef** - \u652f\u6301\u5185\u5b58\u3001Redis\u3001RabbitMQ\u3001SQLite \u4f5c\u4e3a\u961f\u5217\u540e\u7aef\n- **\u91cd\u8bd5\u673a\u5236** - \u5185\u7f6e\u667a\u80fd\u91cd\u8bd5,\u652f\u6301\u6307\u6570\u9000\u907f\u7b56\u7565\n- **\u7b80\u6d01 API** - \u88c5\u9970\u5668\u6a21\u5f0f,\u4e00\u884c\u4ee3\u7801\u5373\u53ef\u5b9a\u4e49\u4efb\u52a1\n- **\u81ea\u52a8\u53d1\u73b0** - \u81ea\u52a8\u626b\u63cf\u76ee\u5f55\u6216\u5305,\u53d1\u73b0\u5e76\u6ce8\u518c\u4efb\u52a1\n- **\u7c7b\u578b\u5b89\u5168** - \u5b8c\u6574\u7684\u7c7b\u578b\u63d0\u793a,IDE \u53cb\u597d\n- **\u914d\u7f6e\u7075\u6d3b** - \u652f\u6301\u4ee3\u7801\u914d\u7f6e\u3001\u6587\u4ef6\u914d\u7f6e(JSON/TOML/YAML)\n- **\u540e\u53f0\u8fd0\u884c** - \u652f\u6301\u5b88\u62a4\u8fdb\u7a0b\u6a21\u5f0f,\u4f18\u96c5\u5173\u95ed\n- **\u4f4e\u5185\u5b58\u5360\u7528** - \u7cbe\u5fc3\u4f18\u5316,\u9002\u5408\u957f\u65f6\u95f4\u8fd0\u884c\n- **\u96f6\u4f9d\u8d56\u542f\u52a8** - \u9ed8\u8ba4\u5185\u5b58\u540e\u7aef,\u65e0\u9700\u5916\u90e8\u670d\u52a1\n\n## \u5b89\u88c5\n\n### \u57fa\u7840\u5b89\u88c5(\u4ec5\u5185\u5b58/SQLite\u540e\u7aef)\n\n```bash\npip install symphra_scheduler\n```\n\n### \u5b89\u88c5 Redis \u652f\u6301\n\n```bash\npip install symphra-scheduler[redis]\n# \u6216\npip install symphra-scheduler redis\n```\n\n### \u5b89\u88c5 RabbitMQ \u652f\u6301\n\n```bash\npip install symphra-scheduler[rabbitmq]\n# \u6216\npip install symphra-scheduler aio-pika\n```\n\n### \u5b8c\u6574\u5b89\u88c5\n\n```bash\npip install symphra-scheduler[all]\n```\n\n## \u5feb\u901f\u5f00\u59cb\n\n### \u57fa\u7840\u7528\u6cd5\n\n```python\nimport asyncio\nfrom symphra_scheduler import Scheduler, cron, interval\n\n# \u521b\u5efa\u8c03\u5ea6\u5668\nscheduler = Scheduler()\n\n# \u4f7f\u7528\u88c5\u9970\u5668\u5b9a\u4e49\u4efb\u52a1\n@cron(\"*/5 * * * * *\") # \u6bcf5\u79d2\u6267\u884c\nasync def task1():\n print(\"\u6bcf5\u79d2\u6267\u884c\u4e00\u6b21\")\n\n@interval(30) # \u6bcf30\u79d2\u6267\u884c\nasync def task2():\n print(\"\u6bcf30\u79d2\u6267\u884c\u4e00\u6b21\")\n\n# \u8fd0\u884c\u8c03\u5ea6\u5668\nasync def main():\n await scheduler.start()\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n### \u4f7f\u7528 Redis \u540e\u7aef\n\n```python\nfrom symphra_scheduler import Scheduler, SchedulerConfig, cron\nfrom symphra_scheduler.backends import RedisBackend\n\n# \u914d\u7f6e Redis \u540e\u7aef\nbackend = RedisBackend(url=\"redis://localhost:6379/0\")\nconfig = SchedulerConfig(max_workers=20)\n\nscheduler = Scheduler(config=config, backend=backend)\n\n@cron(\"0 0 * * *\") # \u6bcf\u5929\u96f6\u70b9\u6267\u884c\nasync def daily_cleanup():\n print(\"\u6267\u884c\u6bcf\u65e5\u6e05\u7406\u4efb\u52a1\")\n await cleanup_old_data()\n\nasync def main():\n await scheduler.start(daemon=True)\n\nasyncio.run(main())\n```\n\n### \u4f7f\u7528 SQLite \u672c\u5730\u6301\u4e45\u5316\n\n```python\nfrom symphra_scheduler import Scheduler, interval\nfrom symphra_scheduler.backends import SQLiteBackend\n\n# SQLite \u540e\u7aef,\u4efb\u52a1\u6301\u4e45\u5316\u5230\u672c\u5730\u6587\u4ef6\nbackend = SQLiteBackend(db_path=\"scheduler.db\")\nscheduler = Scheduler(backend=backend)\n\n@interval(60)\nasync def sync_task():\n print(\"\u540c\u6b65\u6570\u636e...\")\n await sync_data()\n\nasyncio.run(scheduler.start())\n```\n\n### \u4efb\u52a1\u81ea\u52a8\u53d1\u73b0\n\n\u9002\u5408\u6a21\u5757\u5316\u9879\u76ee,\u81ea\u52a8\u626b\u63cf\u5e76\u6ce8\u518c\u4efb\u52a1:\n\n```python\nfrom symphra_scheduler import Scheduler\n\nscheduler = Scheduler()\n\n# \u81ea\u52a8\u53d1\u73b0\u5e76\u6ce8\u518c\u76ee\u5f55\u4e0b\u6240\u6709\u4efb\u52a1\n# \u9879\u76ee\u7ed3\u6784:\n# app/\n# modules/\n# user/task.py\n# email/task.py\n# report/task.py\n\ntasks = scheduler.discover_tasks_from_directory(\"app/modules\")\nprint(f\"\u81ea\u52a8\u53d1\u73b0\u5e76\u6ce8\u518c\u4e86 {len(tasks)} \u4e2a\u4efb\u52a1\")\n\n# \u4f7f\u7528\u81ea\u5b9a\u4e49\u6587\u4ef6\u540d\u6a21\u5f0f\ntasks = scheduler.discover_tasks_from_directory(\n \"app\",\n pattern=\"*_tasks.py\",\n exclude_patterns=[\"test_*.py\"]\n)\n\n# \u4ece\u5305\u4e2d\u53d1\u73b0\ntasks = scheduler.discover_tasks_from_package(\"my_app.tasks\")\n\nasyncio.run(scheduler.start())\n```\n\n### \u9ad8\u7ea7\u7528\u6cd5\n\n```python\nfrom datetime import datetime, timedelta\nfrom symphra_scheduler import Scheduler, scheduled, RetryPolicy\n\nscheduler = Scheduler()\n\n# \u81ea\u5b9a\u4e49\u91cd\u8bd5\u7b56\u7565\n@scheduled(\n interval=10,\n retry_policy=RetryPolicy(\n max_attempts=5,\n strategy=\"exponential\",\n wait_min=1.0,\n wait_max=60.0,\n ),\n timeout=30.0, # 30\u79d2\u8d85\u65f6\n max_instances=3, # \u6700\u591a3\u4e2a\u5e76\u53d1\u5b9e\u4f8b\n tags=[\"critical\", \"data-sync\"],\n)\nasync def important_task():\n \"\"\"\u91cd\u8981\u4efb\u52a1,\u9700\u8981\u91cd\u8bd5\u548c\u8d85\u65f6\u63a7\u5236\"\"\"\n await process_critical_data()\n\n# \u4e00\u6b21\u6027\u4efb\u52a1\nfrom symphra_scheduler.decorators import once\n\n@once(at=datetime(2025, 12, 31, 23, 59, 59))\nasync def new_year_celebration():\n print(\"\u65b0\u5e74\u5feb\u4e50!\")\n```\n\n### \u914d\u7f6e\u6587\u4ef6\u65b9\u5f0f\n\n**config.toml:**\n\n```toml\nmax_workers = 20\nqueue_size = 5000\nshutdown_timeout = 60.0\nenable_logging = true\nlog_level = \"INFO\"\ntimezone = \"Asia/Shanghai\"\npersistence_enabled = true\npersistence_path = \"scheduler_state.json\"\n```\n\n**Python \u4ee3\u7801:**\n\n```python\nfrom symphra_scheduler import Scheduler, SchedulerConfig\n\n# \u4ece\u914d\u7f6e\u6587\u4ef6\u52a0\u8f7d\nconfig = SchedulerConfig.from_file(\"config.toml\")\nscheduler = Scheduler(config=config)\n```\n\n## \u540e\u7aef\u5bf9\u6bd4\n\n| \u540e\u7aef | \u9002\u7528\u573a\u666f | \u6301\u4e45\u5316 | \u5206\u5e03\u5f0f | \u6027\u80fd | \u4f9d\u8d56 |\n|------|---------|--------|--------|------|------|\n| **Memory** | \u5f00\u53d1\u3001\u6d4b\u8bd5\u3001\u5355\u673a | \u2717 | \u2717 | \u2b50\u2b50\u2b50\u2b50\u2b50 | \u65e0 |\n| **SQLite** | \u5355\u673a\u751f\u4ea7\u3001\u9700\u8981\u6301\u4e45\u5316 | \u2713 | \u2717 | \u2b50\u2b50\u2b50\u2b50 | \u65e0 |\n| **Redis** | \u5206\u5e03\u5f0f\u3001\u9ad8\u6027\u80fd | \u2713 | \u2713 | \u2b50\u2b50\u2b50\u2b50\u2b50 | Redis |\n| **RabbitMQ** | \u9ad8\u53ef\u9760\u6027\u3001\u6d88\u606f\u961f\u5217 | \u2713 | \u2713 | \u2b50\u2b50\u2b50\u2b50 | RabbitMQ |\n\n## Cron \u8868\u8fbe\u5f0f\n\nSymphra Scheduler \u652f\u6301\u6807\u51c6 Cron \u8868\u8fbe\u5f0f,\u5e76\u6269\u5c55\u652f\u6301\u79d2\u7ea7\u7cbe\u5ea6:\n\n```\n\u79d2 \u5206 \u65f6 \u65e5 \u6708 \u5468\n\n\u793a\u4f8b:\n*/5 * * * * * - \u6bcf5\u79d2\n0 */10 * * * * - \u6bcf10\u5206\u949f\n0 0 9 * * * - \u6bcf\u5929\u4e0a\u53489\u70b9\n0 0 0 1 * * - \u6bcf\u67081\u53f7\u96f6\u70b9\n0 0 0 * * 1 - \u6bcf\u5468\u4e00\u96f6\u70b9\n*/30 * 9-17 * * 1-5 - \u5de5\u4f5c\u65e59-17\u70b9\u6bcf30\u79d2\n```\n\n## \u76d1\u63a7\u548c\u7edf\u8ba1\n\n```python\n# \u83b7\u53d6\u8c03\u5ea6\u5668\u7edf\u8ba1\u4fe1\u606f\nstats = await scheduler.get_stats()\nprint(stats)\n# {\n# \"running\": true,\n# \"total_tasks\": 5,\n# \"queue_size\": 12,\n# \"active_workers\": 10,\n# \"max_workers\": 20,\n# \"backend\": \"RedisBackend\",\n# \"tasks\": [...]\n# }\n\n# \u83b7\u53d6\u5355\u4e2a\u4efb\u52a1\u7684\u6307\u6807\ntask = scheduler.get_task(\"task_name\")\nprint(task.metrics)\n# TaskMetrics(\n# total_runs=100,\n# successful_runs=95,\n# failed_runs=5,\n# average_execution_time=1.23\n# )\n```\n\n## \u67b6\u6784\u8bbe\u8ba1\n\n```\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Scheduler (\u8c03\u5ea6\u5668) \u2502\n\u2502 - \u4efb\u52a1\u6ce8\u518c\u548c\u7ba1\u7406 \u2502\n\u2502 - \u5de5\u4f5c\u534f\u7a0b\u6c60 \u2502\n\u2502 - \u4f18\u96c5\u5173\u95ed \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u2502\n \u251c\u2500\u2500\u2500 \u88c5\u9970\u5668 API (@cron, @interval)\n \u2502\n \u251c\u2500\u2500\u2500 \u4efb\u52a1\u961f\u5217\n \u2502 \u2514\u2500\u2500\u2500 \u540e\u7aef\u62bd\u8c61\u5c42\n \u2502 \u251c\u2500\u2500\u2500 MemoryBackend\n \u2502 \u251c\u2500\u2500\u2500 SQLiteBackend\n \u2502 \u251c\u2500\u2500\u2500 RedisBackend\n \u2502 \u2514\u2500\u2500\u2500 RabbitMQBackend\n \u2502\n \u2514\u2500\u2500\u2500 \u4efb\u52a1\u6267\u884c\n \u251c\u2500\u2500\u2500 \u8d85\u65f6\u63a7\u5236\n \u251c\u2500\u2500\u2500 \u91cd\u8bd5\u673a\u5236 (tenacity)\n \u251c\u2500\u2500\u2500 \u5e76\u53d1\u63a7\u5236\n \u2514\u2500\u2500\u2500 \u6307\u6807\u6536\u96c6\n```\n\n## \u4e3a\u4ec0\u4e48\u9009\u62e9 Symphra Scheduler?\n\n### vs Celery\n\n- \u2705 **\u66f4\u8f7b\u91cf** - \u65e0\u9700 Redis/RabbitMQ \u5373\u53ef\u8fd0\u884c\n- \u2705 **\u66f4\u7b80\u5355** - \u88c5\u9970\u5668\u5373\u7528,\u65e0\u9700\u989d\u5916\u914d\u7f6e\n- \u2705 **\u66f4\u5feb\u901f** - \u7eaf asyncio,\u65e0\u8fdb\u7a0b\u5f00\u9500\n- \u2705 **\u66f4\u73b0\u4ee3** - Python 3.11+ \u65b0\u7279\u6027,\u5b8c\u6574\u7c7b\u578b\u63d0\u793a\n\n### vs APScheduler\n\n- \u2705 **\u66f4\u9ad8\u6027\u80fd** - \u539f\u751f\u5f02\u6b65,\u4e0d\u662f\u540c\u6b65\u8f6c\u5f02\u6b65\n- \u2705 **\u66f4\u597d\u7684\u53ef\u9760\u6027** - \u7ecf\u8fc7\u4f18\u5316\u7684\u5185\u5b58\u7ba1\u7406\n- \u2705 **\u66f4\u7075\u6d3b** - \u53ef\u63d2\u62d4\u540e\u7aef,\u652f\u6301\u591a\u79cd\u5b58\u50a8\n- \u2705 **\u66f4\u597d\u7684\u53ef\u89c2\u6d4b\u6027** - \u5185\u7f6e\u6307\u6807\u548c\u76d1\u63a7\n\n## \u5f00\u53d1\n\n```bash\n# \u514b\u9686\u4ed3\u5e93\ngit clone https://github.com/getaix/symphra-scheduler.git\ncd symphra-scheduler\n\n# \u5b89\u88c5\u5f00\u53d1\u4f9d\u8d56\npip install -e \".[dev]\"\n\n# \u8fd0\u884c\u6d4b\u8bd5\npytest tests/ -v --cov=symphra_scheduler --cov-report=html\n\n# \u4ee3\u7801\u68c0\u67e5\nruff check symphra_scheduler/\nmypy symphra_scheduler/\n\n# \u683c\u5f0f\u5316\u4ee3\u7801\nblack symphra_scheduler/\n```\n\n## \u8bb8\u53ef\u8bc1\n\nMIT License - \u8be6\u89c1 [LICENSE](LICENSE) \u6587\u4ef6\n\n## \u8d21\u732e\n\n\u6b22\u8fce\u63d0\u4ea4 Issue \u548c Pull Request!\n\n## \u94fe\u63a5\n\n- \ud83d\udcd6 [\u5b8c\u6574\u6587\u6863](https://getaix.github.io/symphra-scheduler)\n- \ud83d\udc1b [\u95ee\u9898\u53cd\u9988](https://github.com/getaix/symphra-scheduler/issues)\n- \ud83d\udce6 [PyPI](https://pypi.org/project/symphra-scheduler/)",
"bugtrack_url": null,
"license": "MIT",
"summary": "A high-performance async task scheduler with cron support, auto-discovery, retry mechanism, and configuration management",
"version": "1.0.2",
"project_urls": {
"Changelog": "https://getaix.github.io/symphra-scheduler/changelog/",
"Documentation": "https://getaix.github.io/symphra-scheduler",
"Homepage": "https://github.com/getaix/symphra-scheduler",
"Issues": "https://github.com/getaix/symphra-scheduler/issues",
"Repository": "https://github.com/getaix/symphra-scheduler"
},
"split_keywords": [
"async",
" asyncio",
" cron",
" queue",
" scheduler",
" task",
" timer"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "49b8fd0678d7a053bd74540fdd9dab80c2075e587ffafd7a7e0fef0cf6bbf341",
"md5": "09de871403634bb4f411cc30ecc7b6fd",
"sha256": "d99b78ea0f259f9cd192ef9ae5b02f1b96d561d0650eb77e0bb0d56a695449f5"
},
"downloads": -1,
"filename": "symphra_scheduler-1.0.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "09de871403634bb4f411cc30ecc7b6fd",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11",
"size": 52309,
"upload_time": "2025-10-26T12:07:45",
"upload_time_iso_8601": "2025-10-26T12:07:45.581616Z",
"url": "https://files.pythonhosted.org/packages/49/b8/fd0678d7a053bd74540fdd9dab80c2075e587ffafd7a7e0fef0cf6bbf341/symphra_scheduler-1.0.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "79bab5c8a50655fe0c6c38419d62237e1eec57df5528ae082e44e568bc0a6283",
"md5": "ec72bc2416ed14fd368197e39ffc944d",
"sha256": "60eefccd9acb55e2837d5322d11e39a3df5a17ccbe42d01927de088b4bb7d4ff"
},
"downloads": -1,
"filename": "symphra_scheduler-1.0.2.tar.gz",
"has_sig": false,
"md5_digest": "ec72bc2416ed14fd368197e39ffc944d",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11",
"size": 120669,
"upload_time": "2025-10-26T12:07:47",
"upload_time_iso_8601": "2025-10-26T12:07:47.127884Z",
"url": "https://files.pythonhosted.org/packages/79/ba/b5c8a50655fe0c6c38419d62237e1eec57df5528ae082e44e568bc0a6283/symphra_scheduler-1.0.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-26 12:07:47",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "getaix",
"github_project": "symphra-scheduler",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"lcname": "symphra-scheduler"
}