
# 스케줄링

Queuety은 반복 작업을 기본으로 지원합니다. `wp_cron`에 의존하는 대신 스케줄을 데이터베이스에 저장하고, 장기 실행 `wp queuety work` 프로세스(또는 워커 풀의 상위 프로세스)가 약 1분마다 스케줄을 확인합니다. `wp queuety work --once`, `wp queuety flush` 및 플러그인에 내장된 WP-Cron 대체 기능은 스케줄을 확인하지 않습니다([#14](https://github.com/inline0/queuety/issues/14)). 장기 실행 워커가 없다면 직접 `wp queuety schedule run`을 실행하세요.

## 간격 기반 스케줄링

간단한 간격 기반 스케줄에는 `every()`을 사용하세요. 표현식은 PHP의 `DateTimeImmutable::modify()`와 호환되는 문자열이면 됩니다:

```php
use Queuety\Queuety;

Queuety::schedule( 'cleanup_handler' )
    ->every( '1 hour' )
    ->on_queue( 'maintenance' );

Queuety::schedule( 'sync_inventory' )
    ->every( '30 minutes' )
    ->on_queue( 'sync' );

Queuety::schedule( 'daily_report', [ 'type' => 'summary' ] )
    ->every( '1 day' );
```

## Cron 스케줄링

표준 5필드 cron 표현식에는 `cron()`을 사용하세요:

```php
// Every day at 3am
Queuety::schedule( 'nightly_cleanup' )
    ->cron( '0 3 * * *' );

// Every Monday at 9am
Queuety::schedule( 'weekly_digest' )
    ->cron( '0 9 * * 1' )
    ->on_queue( 'emails' );

// Every 15 minutes
Queuety::schedule( 'health_check' )
    ->cron( '*/15 * * * *' );
```

## 스케줄 옵션

`PendingSchedule` 빌더는 다음 메서드를 지원합니다:

| 메서드 | 설명 |
|---|---|
| `every( string $interval )` | 간격 표현식 설정 |
| `cron( string $expression )` | cron 표현식 설정 |
| `on_queue( string $queue )` | 대상 대기열 설정(기본값: `'default'`) |
| `overlap( OverlapPolicy $policy )` | 중복 실행 정책 설정(기본값: `Allow`) |

스케줄이 작업을 전달하려면 `every()` 또는 `cron()`을 호출해야 합니다. 둘 다 설정되지 않으면 `RuntimeException`이 발생합니다.

## 중복 실행 정책

다음 주기가 시작될 때 스케줄된 작업이 여전히 실행 중(대기 중 또는 처리 중)이면 중복 실행 정책에 따라 동작이 결정됩니다. `overlap()` 메서드로 정책을 설정하세요:

```php
use Queuety\Queuety;
use Queuety\Enums\OverlapPolicy;

Queuety::schedule( 'sync_inventory' )
    ->every( '5 minutes' )
    ->overlap( OverlapPolicy::Skip )
    ->on_queue( 'sync' );
```

`OverlapPolicy` 열거형에는 세 가지 옵션이 있습니다:

| 정책 | 값 | 동작 |
|---|---|---|
| `OverlapPolicy::Allow` | `allow` | 이전 실행이 여전히 진행 중이어도 항상 새 작업을 전달합니다. 기본값입니다. |
| `OverlapPolicy::Skip` | `skip` | 핸들러에 대기 중이거나 처리 중인 작업이 있으면 이번 주기를 건너뜁니다. 스케줄이 주기를 유지하도록 `next_run`은 정상적으로 업데이트됩니다. |
| `OverlapPolicy::Buffer` | `buffer` | Skip처럼 이번 주기의 작업을 전달하지 않고 `next_run`을 다음 정기 실행 시각으로 이동합니다. Skip과 달리 `last_run`은 업데이트되지 않습니다. |

### Allow(기본값)

같은 핸들러의 여러 인스턴스를 동시에 실행할 수 있습니다. 중복 실행이 무해한 멱등성 핸들러에 사용하세요.

```php
Queuety::schedule( 'send_heartbeat_ping' )
    ->every( '1 minute' )
    ->overlap( OverlapPolicy::Allow );
```

### 건너뛰기

핸들러가 계속 실행 중이면 해당 주기를 아무 알림 없이 건너뜁니다. 두 번째 인스턴스를 실행하는 것이 낭비이거나 충돌을 일으킬 수 있는 핸들러에 사용하세요.

```php
Queuety::schedule( 'rebuild_search_index' )
    ->every( '10 minutes' )
    ->overlap( OverlapPolicy::Skip );
```

### 버퍼

현재는 Skip과 같이 동작합니다. 핸들러에 대기 중이거나 처리 중인 작업이 있으면 해당 주기의 작업을 전달하지 않고 `next_run`을 다음 정기 실행 시각으로 이동합니다. 차이는 Buffer는 `last_run`을 변경하지 않는 반면 Skip은 건너뛴 주기를 마지막 실행으로 기록한다는 점입니다.

```php
Queuety::schedule( 'sync_inventory' )
    ->every( '5 minutes' )
    ->overlap( OverlapPolicy::Buffer );
```

## 작동 방식

스케줄을 만들면 Queuety은 표현식, 핸들러, 페이로드 및 다음 실행 예정 시각과 함께 `queuety_schedules` 테이블에 저장합니다.

스케줄러가 주기를 확인할 때마다(장기 실행 워커에서는 약 1분마다, 또는 `wp queuety schedule run`을 실행할 때) `next_run`이 지난 스케줄을 찾습니다. 실행 시각이 된 각 스케줄에 새 작업을 전달하고 `next_run`을 다음 실행 시각으로 업데이트합니다.

## CLI을 통한 스케줄 관리

```bash
# List all schedules
wp queuety schedule list

# Add a recurring schedule
wp queuety schedule add cleanup_handler --every="1 hour"
wp queuety schedule add nightly_report --cron="0 3 * * *" --queue=reports

# Remove a schedule
wp queuety schedule remove cleanup_handler

# Manually trigger the scheduler
wp queuety schedule run
```

## PHP을 통한 스케줄 관리

```php
// Get the scheduler instance
$scheduler = Queuety::scheduler();

// List all schedules
$schedules = $scheduler->list();

// Remove a schedule by handler name
$scheduler->remove( 'cleanup_handler' );

// Manually trigger a tick
$count = $scheduler->tick();
```

## 페이로드

스케줄에는 전달되는 각 작업에 포함할 정적 페이로드를 지정할 수 있습니다:

```php
Queuety::schedule( 'generate_report', [ 'type' => 'daily', 'format' => 'pdf' ] )
    ->every( '1 day' )
    ->on_queue( 'reports' );
```

스케줄이 실행될 때마다 이 페이로드를 포함한 새 작업이 전달됩니다.
