| Name | chronflow JSON |
| Version |
0.2.1
JSON |
| download |
| home_page | None |
| Summary | A high-performance async task scheduler with cron support, retry mechanism, and configuration management |
| upload_time | 2025-10-24 06:20:30 |
| 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 |
|
# chronflow
[](https://www.python.org/downloads/)
[](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[](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- **\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"
}