
# バッチ処理

バッチを使うと、複数のジョブをまとめてディスパッチし、1つの単位として追跡できます。バッチの完了時、いずれかのジョブの失敗時、または結果にかかわらずバッチ終了時に実行されるコールバックを登録できます。Queuetyが進捗、失敗、キャンセル状態を自動的に追跡します。

## バッチの作成

`Queuety::create_batch()`を使って`BatchBuilder`を開始します。`Contracts\Job`インスタンスの配列を渡し、`dispatch()`を呼び出すと、バッチのレコードとすべてのジョブが作成されます。

```php
use Queuety\Queuety;

$batch = Queuety::create_batch( [
    new ImportUsersJob( $csv_chunk_1 ),
    new ImportUsersJob( $csv_chunk_2 ),
    new ImportUsersJob( $csv_chunk_3 ),
] )
    ->name( 'Import users' )
    ->on_queue( 'imports' )
    ->dispatch();

echo $batch->id; // The batch ID
```

`dispatch()`は、バッチの状態を保持する`Batch`値オブジェクトを返します。

ジョブインスタンスの代わりに、ハンドラーとペイロードの配列を渡すこともできます:

```php
$batch = Queuety::create_batch( [
    [ 'handler' => 'import_users', 'payload' => [ 'chunk' => 1 ] ],
    [ 'handler' => 'import_users', 'payload' => [ 'chunk' => 2 ] ],
] )->dispatch();
```

## コールバック

バッチのライフサイクルの各時点で呼び出すハンドラークラスを登録します。各ハンドラークラスには`handle( Batch $batch )`メソッドが必要です。

```php
$batch = Queuety::create_batch( $jobs )
    ->name( 'Import users' )
    ->then( ImportCompleteHandler::class )
    ->catch( ImportFailedHandler::class )
    ->finally( ImportCleanupHandler::class )
    ->dispatch();
```

| メソッド | 実行されるタイミング |
|---|---|
| `then( $handler_class )` | すべてのジョブが正常に完了したとき（または`allow_failures()`が設定されているとき） |
| `catch( $handler_class )` | バッチ内で最初のジョブが失敗したとき |
| `finally( $handler_class )` | 成功・失敗にかかわらず、バッチが終了したとき |

### コールバックハンドラーの作成

```php
use Queuety\Batch;

class ImportCompleteHandler {
    public function handle( Batch $batch ): void {
        // All users imported. Send a notification.
        error_log( "Batch {$batch->id} completed: {$batch->total_jobs} jobs processed." );
    }
}

class ImportFailedHandler {
    public function handle( Batch $batch ): void {
        error_log( "Batch {$batch->id} had a failure. Failed jobs: {$batch->failed_jobs}" );
    }
}

class ImportCleanupHandler {
    public function handle( Batch $batch ): void {
        // Runs regardless of outcome. Clean up temp files, etc.
    }
}
```

## 失敗を許容する

デフォルトでは、バッチ内のすべてのジョブが成功した場合にのみ`then`コールバックが実行されます。`allow_failures()`を呼び出すと、一部のジョブが失敗しても`then`コールバックが実行されます。

```php
$batch = Queuety::create_batch( $jobs )
    ->then( ReportHandler::class )
    ->allow_failures()
    ->dispatch();
```

## 進捗の追跡

`Batch`値オブジェクトには、進捗を追跡するためのプロパティとメソッドがあります。

```php
$batch = Queuety::find_batch( $batch_id );

$batch->progress();      // 0-100 percentage
$batch->finished();      // true if all jobs are done
$batch->has_failures();  // true if any job failed
$batch->cancelled();     // true if the batch was cancelled

$batch->total_jobs;      // Total number of jobs
$batch->pending_jobs;    // Jobs still pending
$batch->failed_jobs;     // Number of failed jobs
$batch->failed_job_ids;  // Array of failed job IDs
```

| メソッド/プロパティ | 型 | 説明 |
|---|---|---|
| `progress()` | `int` | 0から100までの完了率 |
| `finished()` | `bool` | バッチが終了したかどうか（すべてのジョブが完了または失敗） |
| `has_failures()` | `bool` | バッチ内で失敗したジョブがあるかどうか |
| `cancelled()` | `bool` | バッチがキャンセルされたかどうか |
| `$total_jobs` | `int` | ジョブの合計数 |
| `$pending_jobs` | `int` | 保留中のジョブ数 |
| `$failed_jobs` | `int` | 失敗したジョブ数 |
| `$failed_job_ids` | `array` | 失敗したジョブのID |
| `$name` | `string\|null` | 任意のバッチ名 |
| `$created_at` | `DateTimeImmutable` | バッチの作成日時 |
| `$finished_at` | `DateTimeImmutable\|null` | バッチの終了日時 |
| `$cancelled_at` | `DateTimeImmutable\|null` | バッチのキャンセル日時 |

## キャンセル

`BatchManager`を通じてバッチをキャンセルできます。キャンセルすると`cancelled_at`と`finished_at`が設定され、`finally`コールバックが実行されます。

```php
Queuety::batch_manager()->cancel( $batch_id );
```

キャンセルすると、バッチはキャンセル済みかつ終了済みとしてマークされ、`finally`コールバックが実行されます。ジョブには影響しません。キャンセル済みバッチの保留中のジョブは引き続き実行されますが、その結果でバッチのカウンターが更新されることはなく、`then`、`catch`、`finally`も実行されません。ジョブを実行させない場合は、自分で削除してください。

## バッチの検索

IDでバッチを検索します:

```php
$batch = Queuety::find_batch( $batch_id );

if ( null === $batch ) {
    // Batch not found.
}
```

## 古いバッチの削除

指定した日数より古い、終了済みのバッチを削除します:

```php
$deleted = Queuety::batch_manager()->prune( 30 ); // Delete batches finished > 30 days ago
```

`finished_at`のタイムスタンプがnullでないバッチのみ削除されます。実行中のバッチは削除されません。
