
# 일괄 처리

배치를 사용하면 작업 그룹을 디스패치하고 하나의 단위로 추적할 수 있습니다. 배치가 완료되거나 작업 중 하나가 실패하거나 결과와 관계없이 배치가 끝날 때 실행되는 콜백을 등록할 수 있습니다. 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이 아닌 배치만 삭제됩니다. 활성 배치는 정리 대상이 아닙니다.
