---
title: 排程工作
description: 排程工作依照時間表，對你組織的某個 App 發出一次 HTTP 呼叫，類似 Google Cloud Scheduler。
url: https://agentlab.cresclab.com/docs/zh-tw/deploy/scheduled-jobs
language: zh-Hant-TW
updated: 2026-10-06
---

# 排程工作

排程工作依照時間表，對你組織的某個 App 發出一次 HTTP 呼叫，類似 Google Cloud Scheduler。

## 排程工作的內容

呼叫會打到當下上線的版本。

| 欄位 | 說明                                                                                             |
| ---- | ------------------------------------------------------------------------------------------------ |
| App  | 要呼叫的容器 App。                                                                               |
| 路徑 | 接在 App 網址後面，以 `/` 開頭，可以帶查詢字串，例如 `/tasks/daily`。                            |
| 方法 | `GET`、`POST`、`PUT`、`PATCH` 或 `DELETE`，預設 `POST`。只有 `POST`、`PUT`、`PATCH` 會送出內文。 |
| 排程 | 五個欄位的 cron 運算式：分、時、日、月、星期。最密每分鐘一次。                                   |
| 時區 | 預設 `Asia/Taipei`。                                                                             |

cron 運算式的例子：

| 運算式         | 執行時間        |
| -------------- | --------------- |
| `0 9 * * *`    | 每天 09:00      |
| `*/15 * * * *` | 每 15 分鐘      |
| `0 8 * * 1`    | 每週一 08:00    |
| `0 0 1 * *`    | 每月 1 日 00:00 |

## 建立排程工作

1. **在 App 加一個端點** 例如 `POST /tasks/daily`，把要定期做的事寫在裡面，部署上線。
2. **建立排程工作** 打開「部署 › 排程工作」，選 App，填路徑和排程。
3. **手動執行一次** 用「立即執行」試跑，在執行紀錄確認回應碼和記錄。

## 確認呼叫來自排程

預設的呼叫不帶任何驗證資訊。要讓 App 確認來源，二選一：

- 在排程工作設定自訂標頭，例如 `X-Cron-Secret`，值存成 App 的密鑰，程式裡比對。
- 開啟簽署權杖，呼叫會帶 `Authorization: Bearer <JWT>`。用 `https://api.agentlab.cresclab.com/.well-known/jwks.json` 驗證，`aud` 是 `franky:app:<App ID>`。

## 執行規則

| 項目 | 行為                                                          |
| ---- | ------------------------------------------------------------- |
| 重疊 | 不會重疊。上一次還沒結束時，到期的那一次會略過。              |
| 送達 | 至少送達一次，可能重複。請用 `X-Franky-Run-Id` 標頭去除重複。 |
| 重試 | 預設 0 次，最多 5 次。                                        |
| 逾時 | 15 秒到 30 分鐘，預設 3 分鐘。                                |

```js server.js
const runId = req.headers["x-franky-run-id"];
if (await alreadyHandled(runId)) {
  res.writeHead(200).end();
  return;
}
```
