# ジョブ: スケジュールのみ

## ジョブ: スケジュールのみ

**想定読者:** 固定間隔でジョブを実行し、エージェント起動直後には実行したくない統合担当者。

デフォルトでは、`schedule` のみを指定したジョブは、最初のインターバルが経過するまで待機してから実行します。エージェント起動時に即時実行は行われません。起動直後の実行が運用上の負荷や時期尚早になる場合 (依存サービスの初期化に時間が必要な場合、エージェント再起動のたびにフリート全体で負荷が集中するのを避けたい場合など) に本パターンを使います。起動時にも即座に実行したい場合は、代わりに[ジョブ: スケジュールと起動時](/keeperpam/jp/endpoint-privilege-manager/integrations/examples/job-schedule-and-startup.md)をご参照ください。

本例はWindowsのパスを使います。LinuxおよびmacOSでは、[ジョブ: 最小構成 (Linux)](/keeperpam/jp/endpoint-privilege-manager/integrations/examples/job-minimal-linux.md) および[ジョブ: 最小構成 (macOS)](/keeperpam/jp/endpoint-privilege-manager/integrations/examples/job-minimal-macos.md) の例に示すとおり、パスと `osFilter` を置き換えてください。

## ジョブのJSON <a href="#the-job-json" id="the-job-json"></a>

```json
{
  "id": "my-tool",
  "name": "My Tool",
  "description": "Runs MyTool every 120 minutes. No immediate run on agent startup.",
  "enabled": true,

  "schedule": {
    "intervalMinutes": 120
  },

  "osFilter": {
    "windows": true,
    "linux": false,
    "macOS": false
  },

  "mqttTopics": {
    "allowedPublications": ["KeeperLogger"],
    "allowedSubscriptions": []
  },

  "parameters": [],

  "tasks": [
    {
      "id": "run-tool",
      "name": "Run tool",
      "ExecutionType": "Service",
      "command": "MyTool",
      "executablePath": "C:\\Program Files\\KeeperPrivilegeManager\\Jobs\\bin\\MyTool\\MyTool.exe",
      "arguments": "--keeper-api-base={KeeperApiBaseUrl}",
      "timeoutSeconds": 7200,
      "continueOnFailure": false,
      "scriptType": "Auto"
    }
  ]
}
```

## 変更する箇所 <a href="#what-to-change" id="what-to-change"></a>

<table><thead><tr><th width="239.3333740234375">フィールド</th><th>内容</th></tr></thead><tbody><tr><td><code>id</code></td><td>本ジョブを一意に識別する文字列。ハイフンを使い、アンダースコアは使いません。ファイル名は <code>id</code> と一致させます (例: <code>"id": "my-tool"</code> のときは <code>my-tool.json</code>)。</td></tr><tr><td><code>name</code></td><td>ログや管理画面に表示する名称</td></tr><tr><td><code>schedule.intervalMinutes</code></td><td>実行間隔 (分)。<code>120</code> は2時間ごと。前回の実行が完了してからの経過時間であり、時刻に揃った間隔ではありません。<code>120</code> が「毎正時を起点に2時間ごと」という意味にはなりません。</td></tr><tr><td><code>tasks[0].command</code></td><td>バイナリ名。パスや拡張子は含めません。</td></tr><tr><td><code>tasks[0].executablePath</code></td><td>エンドポイント上のバイナリのフルパス</td></tr><tr><td><code>tasks[0].arguments</code></td><td>バイナリが受け付けるフラグ。<code>{KeeperApiBaseUrl}</code> は残します。</td></tr><tr><td><code>tasks[0].timeoutSeconds</code></td><td>最大実行時間。想定される最長実行時間を十分にカバーする値にしつつ、ハングしたプロセスが長期間未検知のままにならない程度に抑える</td></tr></tbody></table>

## 動作の要点 <a href="#how-this-works" id="how-this-works"></a>

`events` 配列がなく、Startupトリガーもない構成がスケジュールのみです。エージェント起動時にはジョブが読み込まれ、インターバルタイマーが始まりますが、タスクはすぐには実行されません。最初の実行は、スケジューラの初期化から `intervalMinutes` 分経過後です。

`intervalMinutes` は実行間の時間であり、壁時計上の整列ではありません。`intervalMinutes` が `120` でエージェントが09:47に起動した場合、最初の実行はおおよそ11:47前後であり、10:00や12:00にはなりません。時刻に揃えたスケジュールが必要な場合は、代わりに `cronExpression` のスケジュールを使います。

```json
"schedule": {
  "cronExpression": "0 */2 * * *"
}
```

これはエージェント起動時刻に関わらず、偶数時の冒頭 (00:00、02:00、04:00など) に実行されます。

ここでは `timeoutSeconds` を `7200` にし、120分のインターバルに合わせています。一般的には、想定する最長実行時間よりやや長めにタイムアウトを設定し、タスクが完了できる余裕を持たせつつ、次の予定実行の前にハングを検知できるようにします。

## デプロイ前に <a href="#before-you-deploy" id="before-you-deploy"></a>

1. ジョブを登録する前に、エンドポイントの `executablePath` にバイナリをデプロイする。
2. `intervalMinutes` がプレースホルダではなく、実際に欲しい実行間隔になっているか確認する。
3. ファイル名は `id` と一致させる。

## デプロイ <a href="#deploy" id="deploy"></a>

保存前に検証します。

```powershell
Invoke-RestMethod -Method Post `
  -Uri "https://127.0.0.1:6889/api/Jobs/validate" `
  -ContentType "application/json" `
  -Certificate $adminClientCert `
  -Body (Get-Content -Raw .\my-tool.json)
```

ジョブを作成します。

```powershell
Invoke-RestMethod -Method Post `
  -Uri "https://127.0.0.1:6889/api/Jobs" `
  -ContentType "application/json" `
  -Certificate $adminClientCert `
  -Body (Get-Content -Raw .\my-tool.json)
```

ジョブの登録の有無と状態を確認します。

```powershell
Invoke-RestMethod -Method Get `
  -Uri "https://127.0.0.1:6889/api/Jobs/my-tool" `
  -Certificate $adminClientCert
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.keeper.io/keeperpam/jp/endpoint-privilege-manager/integrations/examples/job-schedule-only.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
