chronflow


Namechronflow JSON
Version 0.2.1 PyPI version JSON
download
home_pageNone
SummaryA high-performance async task scheduler with cron support, retry mechanism, and configuration management
upload_time2025-10-24 06:20:30
maintainerNone
docs_urlNone
authorNone
requires_python>=3.11
licenseMIT
keywords async asyncio cron queue scheduler task timer
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            # chronflow

[![Python Version](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)

高性能异步定时任务调度库,专为 Python 3.11+ 设计。

## 特性

- **高性能异步** - 基于 asyncio,支持高并发任务执行
- **秒级精度** - 支持秒级定时任务,基于 Cron 表达式
- **多种后端** - 支持内存、Redis、RabbitMQ、SQLite 作为队列后端
- **重试机制** - 内置智能重试,支持指数退避策略
- **简洁 API** - 装饰器模式,一行代码即可定义任务
- **类型安全** - 完整的类型提示,IDE 友好
- **配置灵活** - 支持代码配置、文件配置(JSON/TOML/YAML)
- **后台运行** - 支持守护进程模式,优雅关闭
- **低内存占用** - 精心优化,适合长时间运行
- **零依赖启动** - 默认内存后端,无需外部服务

## 安装

### 基础安装(仅内存/SQLite后端)

```bash
pip install chronflow
```

### 安装 Redis 支持

```bash
pip install chronflow[redis]
# 或
pip install chronflow redis
```

### 安装 RabbitMQ 支持

```bash
pip install chronflow[rabbitmq]
# 或
pip install chronflow aio-pika
```

### 完整安装

```bash
pip install chronflow[all]
```

## 快速开始

### 基础用法

```python
import asyncio
from chronflow 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 chronflow import Scheduler, SchedulerConfig, cron
from chronflow.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 chronflow import Scheduler, interval
from chronflow.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 datetime import datetime, timedelta
from chronflow 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 chronflow.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 chronflow import Scheduler, SchedulerConfig

# 从配置文件加载
config = SchedulerConfig.from_file("config.toml")
scheduler = Scheduler(config=config)
```

## 后端对比

| 后端 | 适用场景 | 持久化 | 分布式 | 性能 | 依赖 |
|------|---------|--------|--------|------|------|
| **Memory** | 开发、测试、单机 | ✗ | ✗ | ⭐⭐⭐⭐⭐ | 无 |
| **SQLite** | 单机生产、需要持久化 | ✓ | ✗ | ⭐⭐⭐⭐ | 无 |
| **Redis** | 分布式、高性能 | ✓ | ✓ | ⭐⭐⭐⭐⭐ | Redis |
| **RabbitMQ** | 高可靠性、消息队列 | ✓ | ✓ | ⭐⭐⭐⭐ | RabbitMQ |

## Cron 表达式

chronflow 支持标准 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)
                 ├─── 并发控制
                 └─── 指标收集
```

## 为什么选择 chronflow?

### vs Celery

- ✅ **更轻量** - 无需 Redis/RabbitMQ 即可运行
- ✅ **更简单** - 装饰器即用,无需额外配置
- ✅ **更快速** - 纯 asyncio,无进程开销
- ✅ **更现代** - Python 3.11+ 新特性,完整类型提示

### vs APScheduler

- ✅ **更高性能** - 原生异步,不是同步转异步
- ✅ **更好的可靠性** - 经过优化的内存管理
- ✅ **更灵活** - 可插拔后端,支持多种存储
- ✅ **更好的可观测性** - 内置指标和监控

## 开发

```bash
# 克隆仓库
git clone https://github.com/getaix/chronflow.git
cd chronflow

# 安装开发依赖
pip install -e ".[dev]"

# 运行测试
pytest tests/ -v --cov=chronflow --cov-report=html

# 代码检查
ruff check chronflow/
mypy chronflow/

# 格式化代码
black chronflow/
```

## 许可证

MIT License - 详见 [LICENSE](LICENSE) 文件

## 贡献

欢迎提交 Issue 和 Pull Request!

## 链接

- 📖 [完整文档](https://getaix.github.io/chronflow)
- 🐛 [问题反馈](https://github.com/getaix/chronflow/issues)
- 📦 [PyPI](https://pypi.org/project/chronflow/)

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "chronflow",
    "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/e6/f3/8301da45a00c5b14d8b0874fd9801cc054ba2e9fbaacf14ad01fde3cfa14/chronflow-0.2.1.tar.gz",
    "platform": null,
    "description": "# chronflow\n\n[![Python Version](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)\n[![License](https://img.shields.io/badge/license-MIT-green.svg)](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- **\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 chronflow\n```\n\n### \u5b89\u88c5 Redis \u652f\u6301\n\n```bash\npip install chronflow[redis]\n# \u6216\npip install chronflow redis\n```\n\n### \u5b89\u88c5 RabbitMQ \u652f\u6301\n\n```bash\npip install chronflow[rabbitmq]\n# \u6216\npip install chronflow aio-pika\n```\n\n### \u5b8c\u6574\u5b89\u88c5\n\n```bash\npip install chronflow[all]\n```\n\n## \u5feb\u901f\u5f00\u59cb\n\n### \u57fa\u7840\u7528\u6cd5\n\n```python\nimport asyncio\nfrom chronflow 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 chronflow import Scheduler, SchedulerConfig, cron\nfrom chronflow.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 chronflow import Scheduler, interval\nfrom chronflow.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### \u9ad8\u7ea7\u7528\u6cd5\n\n```python\nfrom datetime import datetime, timedelta\nfrom chronflow 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 chronflow.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 chronflow 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\nchronflow \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 chronflow?\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/chronflow.git\ncd chronflow\n\n# \u5b89\u88c5\u5f00\u53d1\u4f9d\u8d56\npip install -e \".[dev]\"\n\n# \u8fd0\u884c\u6d4b\u8bd5\npytest tests/ -v --cov=chronflow --cov-report=html\n\n# \u4ee3\u7801\u68c0\u67e5\nruff check chronflow/\nmypy chronflow/\n\n# \u683c\u5f0f\u5316\u4ee3\u7801\nblack chronflow/\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/chronflow)\n- \ud83d\udc1b [\u95ee\u9898\u53cd\u9988](https://github.com/getaix/chronflow/issues)\n- \ud83d\udce6 [PyPI](https://pypi.org/project/chronflow/)\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A high-performance async task scheduler with cron support, retry mechanism, and configuration management",
    "version": "0.2.1",
    "project_urls": {
        "Changelog": "https://getaix.github.io/chronflow/changelog/",
        "Documentation": "https://getaix.github.io/chronflow",
        "Homepage": "https://github.com/getaix/chronflow",
        "Issues": "https://github.com/getaix/chronflow/issues",
        "Repository": "https://github.com/getaix/chronflow"
    },
    "split_keywords": [
        "async",
        " asyncio",
        " cron",
        " queue",
        " scheduler",
        " task",
        " timer"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "d204ab297b5b67b8f87eb958c6126d38e3e9b4eceba4cd01279e3687ba9a32cc",
                "md5": "6ccf4b5e88a1e1c603015b461c1178c7",
                "sha256": "7d219ab9fda3e80e0a50d8ca827f3701c93a449e4114edb91557fb0845a0e09f"
            },
            "downloads": -1,
            "filename": "chronflow-0.2.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "6ccf4b5e88a1e1c603015b461c1178c7",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.11",
            "size": 47522,
            "upload_time": "2025-10-24T06:20:29",
            "upload_time_iso_8601": "2025-10-24T06:20:29.615186Z",
            "url": "https://files.pythonhosted.org/packages/d2/04/ab297b5b67b8f87eb958c6126d38e3e9b4eceba4cd01279e3687ba9a32cc/chronflow-0.2.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "e6f38301da45a00c5b14d8b0874fd9801cc054ba2e9fbaacf14ad01fde3cfa14",
                "md5": "aee4f44e3644b66a24d434fbed04c111",
                "sha256": "04959b964cc8f2d4090802121d09ba43e81d741e0f2055e39112c995744fa973"
            },
            "downloads": -1,
            "filename": "chronflow-0.2.1.tar.gz",
            "has_sig": false,
            "md5_digest": "aee4f44e3644b66a24d434fbed04c111",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.11",
            "size": 92555,
            "upload_time": "2025-10-24T06:20:30",
            "upload_time_iso_8601": "2025-10-24T06:20:30.879267Z",
            "url": "https://files.pythonhosted.org/packages/e6/f3/8301da45a00c5b14d8b0874fd9801cc054ba2e9fbaacf14ad01fde3cfa14/chronflow-0.2.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-24 06:20:30",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "getaix",
    "github_project": "chronflow",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": true,
    "lcname": "chronflow"
}
        
Elapsed time: 0.89865s