279 lines
7.9 KiB
Markdown
279 lines
7.9 KiB
Markdown
# 公开定时任务 API
|
||
|
||
本文档描述用于对接外部系统的**公开只读**定时任务接口,以及配套的公开网页入口。所有 `/api/public/*` 接口都**无需登录**,可以直接调用。
|
||
|
||
> ⚠️ 任何接入这套接口的系统需要确认:暴露 task / run 列表与正文是符合贵方业务安全要求的。如果不希望全员可见,请走带鉴权的 `/api/scheduled-tasks/*`。
|
||
|
||
---
|
||
|
||
## 1. 基础信息
|
||
|
||
| 项 | 值 |
|
||
|---|---|
|
||
| 网关基址(开发) | `http://localhost:8001` |
|
||
| 网关基址(生产) | 部署到 Nginx 后通常是 `https://<你的域名>` |
|
||
| 公开 API 前缀 | `/api/public/scheduled-tasks` |
|
||
| 鉴权 | **无需**鉴权(白名单在 `auth_middleware._PUBLIC_PATH_PREFIXES`) |
|
||
| 编码 | 请求 / 响应均为 UTF-8,响应类型 `application/json`(下载除外) |
|
||
| 错误响应 | 标准 FastAPI 错误体 `{"detail": "..."}`;HTTP 状态码 `404 / 400 / 500` 等 |
|
||
|
||
公开网页页面:
|
||
|
||
```
|
||
#/public/scheduled-tasks/<task_id>
|
||
```
|
||
|
||
例如 `https://<你的域名>/#/public/scheduled-tasks/8f1d8b9c-...`。
|
||
左侧列出该任务所有执行记录,默认打开第一条;右侧默认渲染 Markdown 正文,点击 Tab 可以查看“结果文件”或“元数据”,点击左侧任意记录右侧内容会跟随切换。
|
||
|
||
---
|
||
|
||
## 2. 接口列表
|
||
|
||
### 2.1 列出全部定时任务
|
||
|
||
```
|
||
GET /api/public/scheduled-tasks
|
||
```
|
||
|
||
**Query 参数**
|
||
|
||
| 名称 | 类型 | 必填 | 默认 | 说明 |
|
||
|---|---|---|---|---|
|
||
| `search` | string | 否 | — | 任务名模糊匹配(不区分大小写) |
|
||
| `limit` | int | 否 | 200 | 单页数量,1–500 |
|
||
| `offset` | int | 否 | 0 | 偏移量,配合 `limit` 分页 |
|
||
|
||
**响应**
|
||
|
||
```json
|
||
{
|
||
"total": 12,
|
||
"limit": 200,
|
||
"offset": 0,
|
||
"tasks": [
|
||
{
|
||
"task_id": "8f1d8b9c-...",
|
||
"name": "每日舆情简报",
|
||
"schedule_text": "每天 09:00",
|
||
"cron_expr": "0 9 * * *",
|
||
"timezone": "Asia/Shanghai",
|
||
"enabled": true,
|
||
"next_run_at": "2026-05-21T01:00:00+00:00",
|
||
"last_run_at": "2026-05-20T01:00:12+00:00",
|
||
"last_status": "succeeded",
|
||
"published": true
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
> 已脱敏:`user_id`、`creator_email`、`prompt`、`scheduler_thread_id`、`execution_context` 等私有字段不会出现在公开响应里。
|
||
|
||
### 2.2 获取单个任务元数据
|
||
|
||
```
|
||
GET /api/public/scheduled-tasks/{task_id}
|
||
```
|
||
|
||
**响应**:与上面 `tasks[]` 的元素结构一致;任务不存在返回 `404`。
|
||
|
||
### 2.3 列出某任务的所有执行记录
|
||
|
||
```
|
||
GET /api/public/scheduled-tasks/{task_id}/runs
|
||
```
|
||
|
||
**Query 参数**
|
||
|
||
| 名称 | 类型 | 必填 | 默认 | 说明 |
|
||
|---|---|---|---|---|
|
||
| `limit` | int | 否 | 50 | 最近执行数量,1–200 |
|
||
|
||
**响应**
|
||
|
||
```json
|
||
{
|
||
"task": { "task_id": "...", "name": "...", "schedule_text": "...", "timezone": "...", "enabled": true },
|
||
"total": 7,
|
||
"runs": [
|
||
{
|
||
"id": "run-uuid-...",
|
||
"task_id": "8f1d8b9c-...",
|
||
"scheduled_for": "2026-05-20T01:00:00+00:00",
|
||
"started_at": "2026-05-20T01:00:01+00:00",
|
||
"finished_at": "2026-05-20T01:00:12+00:00",
|
||
"status": "succeeded",
|
||
"error": null,
|
||
"retry_count": 0,
|
||
"result": {
|
||
"title": "2026-05-20 舆情简报",
|
||
"content": "# 简报\n\n...",
|
||
"format": "markdown",
|
||
"files": [
|
||
{ "index": 0, "name": "report.md", "mime_type": "text/markdown", "kind": "markdown", "size": 4321 }
|
||
],
|
||
"created_at": "2026-05-20T01:00:12+00:00"
|
||
}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
> 已脱敏:返回的 `files[]` 不包含服务器绝对路径;客户端通过下标 `index` 调用文件接口。
|
||
|
||
### 2.4 获取单条执行记录
|
||
|
||
```
|
||
GET /api/public/scheduled-tasks/runs/{run_id}
|
||
```
|
||
|
||
返回单条 run 数据(结构同 2.3 中的 `runs[]` 元素)。
|
||
|
||
### 2.5 获取单个结果文件的内容(可预览文本直接内联)
|
||
|
||
```
|
||
GET /api/public/scheduled-tasks/runs/{run_id}/files/{file_index}
|
||
```
|
||
|
||
`file_index` 来自 `run.result.files[].index`。
|
||
|
||
**响应**
|
||
|
||
```json
|
||
{
|
||
"index": 0,
|
||
"name": "report.md",
|
||
"mime_type": "text/markdown",
|
||
"kind": "markdown",
|
||
"size": 4321,
|
||
"previewable": true,
|
||
"content": "# 简报\n\n..."
|
||
}
|
||
```
|
||
|
||
二进制文件 `previewable=false`、`content=null`,请走 2.6 下载。
|
||
|
||
### 2.6 下载单个结果文件
|
||
|
||
```
|
||
GET /api/public/scheduled-tasks/runs/{run_id}/files/{file_index}/download
|
||
```
|
||
|
||
返回原始文件二进制流,附带 `Content-Disposition: attachment` 头部。
|
||
|
||
### 2.7 打包下载整个执行结果
|
||
|
||
```
|
||
GET /api/public/scheduled-tasks/runs/{run_id}/download
|
||
```
|
||
|
||
- 如果该 run **没有附加文件**:直接返回 `result.md`(UTF-8 BOM)。
|
||
- 如果有 ≥ 1 个附加文件:返回 ZIP,里面包含:
|
||
- `result.md` — 标题 + 正文 Markdown
|
||
- 每个生成文件原样
|
||
|
||
---
|
||
|
||
## 3. 调用示例
|
||
|
||
### curl
|
||
|
||
```bash
|
||
# 列出全部任务
|
||
curl -s "https://<domain>/api/public/scheduled-tasks?limit=50"
|
||
|
||
# 查看任务的执行记录
|
||
curl -s "https://<domain>/api/public/scheduled-tasks/<task_id>/runs"
|
||
|
||
# 下载某次执行
|
||
curl -L -o report.zip \
|
||
"https://<domain>/api/public/scheduled-tasks/runs/<run_id>/download"
|
||
```
|
||
|
||
### Python
|
||
|
||
```python
|
||
import requests
|
||
|
||
base = "https://<domain>/api/public/scheduled-tasks"
|
||
|
||
tasks = requests.get(f"{base}", params={"limit": 100, "search": "舆情"}).json()
|
||
for task in tasks["tasks"]:
|
||
runs = requests.get(f"{base}/{task['task_id']}/runs", params={"limit": 5}).json()
|
||
for run in runs["runs"]:
|
||
if run.get("result"):
|
||
print(task["name"], run["id"], run["result"]["title"])
|
||
print(run["result"]["content"][:200])
|
||
```
|
||
|
||
### 直接嵌入 iframe
|
||
|
||
```html
|
||
<iframe src="https://<domain>/#/public/scheduled-tasks/<task_id>"
|
||
style="width:100%;height:800px;border:0"></iframe>
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 状态码
|
||
|
||
| 状态码 | 含义 |
|
||
|---|---|
|
||
| 200 | 成功 |
|
||
| 400 | 参数错误(如 `limit` 超出范围) |
|
||
| 404 | 任务 / 执行 / 文件 不存在 |
|
||
| 5xx | 网关 / 后台错误 |
|
||
|
||
---
|
||
|
||
## 5. 字段映射快查
|
||
|
||
### `task` 字段
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| `task_id` | string | 任务 ID |
|
||
| `name` | string | 任务名 |
|
||
| `schedule_text` | string | 人类可读的执行计划 |
|
||
| `cron_expr` | string | 规范化的 cron 表达式 |
|
||
| `timezone` | string | 时区 |
|
||
| `enabled` | bool | 是否启用 |
|
||
| `next_run_at` | string | null | 下次执行时间(ISO 8601) |
|
||
| `last_run_at` | string | null | 上次执行时间 |
|
||
| `last_status` | string | null | 上次执行状态(`succeeded` / `failed` / `running` / `pending` / `…`) |
|
||
| `published` | bool | 是否被发布到广场 |
|
||
|
||
### `run` 字段
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| `id` | string | 执行 ID |
|
||
| `task_id` | string | 所属任务 ID |
|
||
| `scheduled_for` | string | 原定执行时间 |
|
||
| `started_at` | string | null | 实际开始时间 |
|
||
| `finished_at` | string | null | 完成 / 失败时间 |
|
||
| `status` | string | `pending` / `running` / `succeeded` / `failed` |
|
||
| `error` | string | null | 失败描述 |
|
||
| `retry_count` | int | null | 重试次数 |
|
||
| `result` | object | null | 执行结果(见下) |
|
||
|
||
### `result` 字段
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| `title` | string | 结果标题 |
|
||
| `content` | string | 主体 Markdown / 文本 |
|
||
| `format` | string | `markdown` / `text` / `json` / `mixed` |
|
||
| `files[]` | array | 附加文件元数据,含 `index / name / mime_type / kind / size` |
|
||
| `created_at` | string | 结果生成时间 |
|
||
|
||
---
|
||
|
||
## 6. 实现位置
|
||
|
||
- 路由实现:[`app/gateway/routers/public_scheduled_tasks.py`](../app/gateway/routers/public_scheduled_tasks.py)
|
||
- 公开 URL 白名单:[`app/gateway/auth_middleware.py`](../app/gateway/auth_middleware.py) 中的 `_PUBLIC_PATH_PREFIXES`
|
||
- 前端公开页面:[`frontend-web/src/pages/PublicScheduledTaskPage.tsx`](../../../frontend-web/src/pages/PublicScheduledTaskPage.tsx)
|
||
- 路由注册:[`frontend-web/src/App.tsx`](../../../frontend-web/src/App.tsx) `/#/public/scheduled-tasks/:taskId`
|