# 実行

> Nodaro のワークフローの実行をノードごとに追跡し、各ノードの結果を読み取ります。過去の実行を一覧表示し、実行をすぐに、または実行中のノードの完了後にキャンセルします。

Source: https://nodaro.ai/ja/docs/developers/api/executions

**実行**（execution）は、ワークフロー全体を 1 回実行したものです。実行には、そのステータス、完了したノードの数、使用したクレジット、すべてのノードの状態と結果が記録されます。また、その実行で作成されたジョブも、AI ノードごとに 1 つずつまとめられます。`POST /v1/workflows/:id/run` は `executionId` を返し、実行のエンドポイントで、その実行を最後まで追跡できます。

## エンドポイント
| メソッド | パス | 説明 |
| --- | --- | --- |
| `GET` | `/v1/workflow-executions/:id` | 1 件の実行について、ステータス、ノード数、クレジット、すべてのノードの状態を返します。 |
| `GET` | `/v1/workflow-executions/:id/stream` | 同じ実行を、Server-Sent Events のストリームとして返します。 |
| `GET` | `/v1/workflows/:id/executions` | 1 つのワークフローの実行を、ページ単位で返します。 |
| `POST` | `/v1/workflow-executions/:id/cancel` | 実行を、すぐに、または実行中のノードの完了後にキャンセルします。 |
| `GET` | `/v1/api/status/:execId` | API トークン用のルートです。実行のステータス、ノード数、使用したクレジットを返します。 |
| `GET` | `/v1/api/result/:execId` | API トークン用のルートです。完了した実行の出力を返します。 |

最後の 2 つは、`POST /v1/api/run` で開始した実行のためのものです。詳しくは、[新しい入力値でワークフローを実行する](https://nodaro.ai/docs/developers/api/workflows#run-a-workflow-with-new-input-values)で説明しています。

## 実行の取得
**curl**

```bash
curl -s https://app.nodaro.ai/v1/workflow-executions/3f9e2b1a-7c6d-4e5f-8a9b-0c1d2e3f4a5b \
  -H "Authorization: Bearer $NODARO_API_KEY"
```

**TypeScript SDK**

```ts
const { data } = await client.executions.get(executionId)
console.log(data.status, `${data.completedNodes}/${data.totalNodes}`)
```

**CLI**

```bash
nodaro executions get 3f9e2b1a-7c6d-4e5f-8a9b-0c1d2e3f4a5b --json
```

```json
{
"data": {
"id": "3f9e2b1a-7c6d-4e5f-8a9b-0c1d2e3f4a5b",
"workflowId": "8c2d7f1e-3a4b-4c5d-9e6f-7a8b9c0d1e2f",
"status": "running",
"triggerType": "manual",
"totalNodes": 4,
"completedNodes": 2,
"failedNodes": 0,
"totalCreditsUsed": 45,
"errorMessage": null,
"nodeStates": {
"text-prompt-1": { "status": "completed", "output": { "text": "a knight on a hill at dawn" } },
"generate-image-1": { "status": "completed", "output": { "imageUrl": "https://…/knight.png" } },
"generate-video-1": { "status": "running" },
"add-captions-1": { "status": "pending" }
},
"completedAt": null
}
}
```

| フィールド | 意味 |
| --- | --- |
| `status` | 実行のステータスです。下の表を参照してください。 |
| `triggerType` | 実行を開始したものです。`manual`、`webhook`、`schedule`、`app_run`、`single-node` などがあります。 |
| `totalNodes`、`completedNodes`、`failedNodes` | ノード数です。進行状況は `completedNodes / totalNodes` で表示します。 |
| `totalCreditsUsed` | その実行がこれまでに使ったクレジットです。 |
| `errorMessage` | 実行が失敗または停止した理由を、文章で示します。 |
| `nodeStates` | すべてのノードの状態で、ノード ID をキーとしています。 |
| `completedAt` | 実行が終了した日時、または `null` です。 |

単独で実行した 1 つのノードのジョブの ID も、ここで使えます。その場合、サーバーは同じ形式で、その 1 つのノードについての情報を返します。存在しない ID や、自分のものではない ID には、`404` が返ります。

### 実行のステータス
| ステータス | 最終状態 | 意味 |
| --- | --- | --- |
| `pending` | いいえ | 実行はキューで待機しています。 |
| `running` | いいえ | ノードを実行しています。 |
| `stopping` | いいえ | `after_current` でキャンセルしました。実行中のノードが完了した後、実行が停止します。 |
| `completed` | はい | 実行が完了しました。 |
| `failed` | はい | 実行が失敗しました。理由は `errorMessage` に示されます。 |
| `cancelled` | はい | 実行がキャンセルされました。 |
| `timed_out` | はい | 実行がタイムアウトしました。 |
| `discarded` | はい | `discard` でキャンセルしました。実行中だったジョブは完了しましたが、キャンバスは更新されていません。 |

### ノードの状態
`nodeStates` の各エントリーには `status` があり、値は `pending`、`running`、`completed`、`failed`、`skipped` のいずれかです。失敗したノードには、`error` も含まれます。

完了したノードは、結果を `output` に持っています。キーはノードの出力によって異なります。`url`、`imageUrl`、`videoUrl`、`audioUrl`、`resultUrl`、`text` の順に探してください。

実行が構造化された結果を保持した場合は、**失敗した**ノードにも `output` が含まれることがあります。現在これに当てはまるのは、3D シーンを作成するノードです。すべての修正を試してもビジュアルレビューに通らなかったシーンでも、下書きは出力されます。その場合、ノードは、その下書きを `output.plan` に入れた状態で失敗します。ここから、次の 2 つのルールが導かれます。

- **ステータスではなく、フィールドの有無を確認します**。`pending` や `running` のノードに `output` があることはありません。また、今後はほかの種類のノードも結果を保持する可能性があります。
- **`output` があることは、成功を意味しません**。ノードは失敗しており、何かを保持しているだけです。

SDK は、`completed` と `failed` で `true` を返す `nodeStateMayCarryOutput(status)` と、同じ 2 つのステータスをまとめた `OUTPUT_BEARING_NODE_STATUSES` をエクスポートしています。

## 実行の終了を待つ
ステータスが最終状態になるまで、2〜5 秒ごとにポーリングします。

**TypeScript SDK**

```ts
const { executionId } = await client.workflows.run(workflowId)

const final = ['completed', 'failed', 'cancelled', 'timed_out', 'discarded']
while (true) {
const { data } = await client.executions.get(executionId)
console.log(`${data.completedNodes}/${data.totalNodes} nodes done`)
if (final.includes(data.status)) {
if (data.status !== 'completed') throw new Error(`Run ${data.status}: ${data.errorMessage ?? 'no message'}`)
console.log(`Done. Used ${data.totalCreditsUsed} credits.`)
break
}
await new Promise((r) => setTimeout(r, 2_000))
}
```

**curl**

```bash
while true; do
STATUS=$(curl -s -H "Authorization: Bearer $NODARO_API_KEY" \
"https://app.nodaro.ai/v1/workflow-executions/$EXEC" | jq -r .data.status)
echo "Status: $STATUS"
case "$STATUS" in completed|failed|cancelled|timed_out|discarded) break;; esac
sleep 3
done
```

**CLI**

```bash
nodaro executions get 3f9e2b1a-7c6d-4e5f-8a9b-0c1d2e3f4a5b --watch
```

`--watch` を付けると、CLI は実行が終わるまでポーリングし、成功した場合はコード `0`、実行が失敗した場合は `2`、キャンセルされた場合は `130` で終了します。`--json` を付けると、ペイロードを出力して正常終了するので、`.status` を自分で確認してください。

`GET /v1/workflow-executions/:id/stream` は、実行中、同じ実行の状態を Server-Sent Events として送ります。ノードの `output` のルールも、上記の読み取りと同じです。ほとんどの連携では、ポーリングのほうが簡単です。

## ワークフローの実行の一覧
`GET /v1/workflows/:id/executions` は、ワークフローの実行を `{ data, nextCursor }` の形式で、ページ単位で返します。この一覧には、ワークフロー全体の実行に加えて、そのワークフローで単独で実行したノードのジョブも含まれます。

| クエリパラメーター | 意味 |
| --- | --- |
| `limit` | ページのサイズです。 |
| `cursor` | 前のページの `nextCursor` です。 |
| `status` | カンマ区切りのステータスです。たとえば `pending,running` のように指定します。 |
| `source` | `editor` は、アプリ、Webhook、スケジュールで開始した実行を除外します。`all` は、それらも含めます。 |

**curl**

```bash
curl -s "https://app.nodaro.ai/v1/workflows/$WORKFLOW_ID/executions?limit=20&status=completed" \
  -H "Authorization: Bearer $NODARO_API_KEY"
```

**TypeScript SDK**

```ts
const { data, nextCursor } = await client.executions.listForWorkflow(workflowId, {
limit: 20,
status: 'completed',
})
```

## 実行のキャンセル
`POST /v1/workflow-executions/:id/cancel` は、実行を停止します。リクエストボディの任意の `mode` で、すでに実行中のノードの扱いが決まります。

| `mode` | 動作 | 最終ステータス |
| --- | --- | --- |
| なし | 実行はすぐに停止します。実行中のジョブはキャンセルされ、確保されていたクレジットは返還されます。 | `cancelled` |
| `after_current` | 実行中のノードは完了し、その結果はキャンバスとライブラリに保存されます。その後、実行が停止します。 | `stopping` の後、最終ステータス |
| `discard` | 新しいノードは開始されません。実行中のジョブはモデル側で止められないため、完了してライブラリに保存されますが、結果はキャンバスに書き込まれません。それらのジョブは完了しているため、返還はありません。 | `discarded` |

レスポンスは `{ "success": true }` です。

**curl**

```bash
curl -s -X POST https://app.nodaro.ai/v1/workflow-executions/$EXEC/cancel \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mode": "after_current"}'
```

**TypeScript SDK**

```ts
await client.executions.cancel(executionId)                           // now
await client.executions.cancel(executionId, { mode: 'after_current' }) // after running nodes
await client.executions.cancel(executionId, { mode: 'discard' })       // stop scheduling
```

**CLI**

```bash
nodaro executions cancel 3f9e2b1a-7c6d-4e5f-8a9b-0c1d2e3f4a5b                # now
nodaro executions cancel 3f9e2b1a-7c6d-4e5f-8a9b-0c1d2e3f4a5b --mode stopping # after running nodes
```

実行全体ではなく 1 つの生成だけを止めるには、そのジョブをキャンセルします。[ジョブ](https://nodaro.ai/docs/developers/api/jobs#cancel-or-delete-a-job)を参照してください。

## 実行とジョブ
実行の AI ノードは、それぞれ[ジョブ](https://nodaro.ai/docs/developers/api/jobs)を 1 つ作成し、ジョブが終わると、そのノードの結果が `nodeStates` に入ります。実行全体を追跡するには、実行を読み取ります。1 回の生成の詳細を確認するには、ジョブを読み取ります。ジョブからは、`error_hint`、`credit_status`、そして `input_data` に記録された、モデルに送られた内容のすべてがわかります。

[**Webhook トリガー**（Webhook Trigger）](https://nodaro.ai/docs/nodes/automate/webhook-trigger)の呼び出しや[**スケジュールトリガー**（Schedule Trigger）](https://nodaro.ai/docs/nodes/automate/schedule-trigger)の起動など、トリガーが開始した実行も実行であり、`triggerType` は `webhook` または `schedule` になります。[Webhook](https://nodaro.ai/docs/developers/api/webhooks) を参照してください。

## Frequently asked questions

### 実行（execution）とジョブの違いは何ですか？

実行は、ワークフロー全体を 1 回実行したものです。すべてのノードの状態を記録し、その実行で作成されたジョブを、AI ノードごとに 1 つずつまとめます。ジョブは、1 枚の画像や 1 本の動画のレンダリングなど、1 回の生成です。

### ワークフローの実行のステータスは、どうすれば取得できますか？

GET /v1/workflow-executions/:id を 2〜5 秒ごとにポーリングします。実行のステータス、完了したノードと失敗したノードの数、それまでに使ったクレジット、すべてのノードの状態が返ります。ステータスが completed、failed、cancelled、timed_out、discarded のいずれかになったら、ポーリングを止めます。

### ワークフローの実行は、どうすればキャンセルできますか？

POST /v1/workflow-executions/:id/cancel を送ります。mode を指定しない場合はすぐにキャンセルされ、確保されたクレジットは返還されます。mode に after_current を指定すると、実行中のノードが先に完了します。mode に discard を指定すると、実行中のジョブは完了しますが、新しいノードは開始されません。

### 実行の中で、ノードの結果はどこにありますか？

nodeStates の中の、そのノードの ID の下にあります。完了したノードは、結果を output に持っています。たとえば、output.imageUrl、output.videoUrl、output.audioUrl、output.text です。

### ワークフローの過去の実行を一覧表示できますか？

はい。GET /v1/workflows/:id/executions は、ワークフローの実行をページ単位で返します。ステータスや、実行を開始した場所で絞り込むこともできます。
