Metadata-Version: 2.4
Name: llm-async-scheduler
Version: 0.1.2
Summary: 基于 APScheduler 的异步任务调度通用库，支持 cron、interval 与 manual 触发模式。
License-Expression: MIT
License-File: LICENSE
Keywords: apscheduler,async,cron,scheduler,task
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.12
Requires-Dist: apscheduler<4,>=3.10.4
Description-Content-Type: text/markdown

# llm-async-scheduler

基于 [APScheduler](https://apscheduler.readthedocs.io/) 的异步任务调度通用库，提供统一的任务抽象与 cron / interval / manual 三种触发模式。

> PyPI 包名：`llm-async-scheduler`，import 名：`async_scheduler`。

## 特性

- 统一的 `ScheduleTask` 基类，内置超时、重试与生命周期钩子
- 基于 `AsyncIOScheduler` 的 cron 与 interval 调度
- manual 模式支持按需手动触发
- Python 3.12+，纯 asyncio

## 安装

```bash
pip install llm-async-scheduler
```

或使用 [uv](https://docs.astral.sh/uv/)：

```bash
uv add llm-async-scheduler
```

## 快速开始

### 定义任务

继承 `ScheduleTask` 并实现 `run()`：

```python
import asyncio
from async_scheduler import AsyncTaskScheduler, ScheduleTask


class HelloTask(ScheduleTask):
    async def run(self) -> None:
        print(f"hello from {self.task_id}")


async def main() -> None:
    task = HelloTask("hello", timeout=30, retry_times=1, tags=["demo"])
    scheduler = AsyncTaskScheduler(task, "manual")
    await scheduler.run_manual_once()


asyncio.run(main())
```

### Cron 调度

```python
import asyncio
from async_scheduler import AsyncTaskScheduler, ScheduleTask


class SyncDataTask(ScheduleTask):
    async def run(self) -> None:
        # 业务逻辑
        ...


async def main() -> None:
    task = SyncDataTask("sync-data")
    scheduler = AsyncTaskScheduler(
        task,
        "cron",
        cron_expr="0 */6 * * *",  # 每 6 小时
    )
    scheduler.start()
    await scheduler.wait_until_done()  # 常驻进程，可通过 stop() 退出


asyncio.run(main())
```

### Interval 调度

```python
scheduler = AsyncTaskScheduler(
    task,
    "interval",
    interval_seconds=60,
)
scheduler.start()
await scheduler.wait_until_done()
```

## API 概览

### ScheduleTask

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `task_id` | `str` | — | 任务唯一标识 |
| `timeout` | `int` | `3600` | 单次执行超时（秒） |
| `retry_times` | `int` | `0` | 失败后重试次数 |
| `retry_delay` | `int` | `5` | 重试间隔（秒） |
| `tags` | `Sequence[str]` | `[]` | 可选标签，便于日志与监控 |

可覆写钩子：

- `before_run()`：执行前
- `run()`：核心业务（必须实现）
- `after_run(success)`：执行后
- `on_error(exc)`：每次失败时

调度器调用 `safe_execute()`，不要直接调用 `run()`。

### AsyncTaskScheduler

| 参数 | 类型 | 说明 |
|------|------|------|
| `task` | `ScheduleTask` | 任务实例 |
| `trigger_mode` | `"cron" \| "interval" \| "manual"` | 触发模式 |
| `cron_expr` | `str \| None` | cron 表达式（5 段，如 `0 2 * * *`） |
| `interval_seconds` | `int \| None` | interval 间隔秒数 |

常用方法：

| 方法 | 说明 |
|------|------|
| `start()` | 启动调度（manual 模式可跳过） |
| `stop()` | 停止调度并唤醒 `wait_until_done()` |
| `run_manual_once()` | manual 模式手动执行一次 |
| `wait_until_done()` | 阻塞等待结束或 shutdown |
| `request_shutdown()` | 仅唤醒 `wait_until_done()`，不停止 job |

## 许可证

[MIT](./LICENSE)
