
# Penjadwalan

Queuety memiliki dukungan bawaan untuk pekerjaan berulang. Alih-alih mengandalkan `wp_cron`, jadwal disimpan di database dan dievaluasi oleh proses `wp queuety work` yang berjalan lama (atau proses induk dari pool worker) kira-kira sekali per menit. `wp queuety work --once`, `wp queuety flush`, dan fallback WP-Cron bawaan plugin tidak mengevaluasi jadwal ([#14](https://github.com/inline0/queuety/issues/14)); tanpa worker yang berjalan lama, jalankan `wp queuety schedule run` sendiri.

## Penjadwalan interval

Gunakan `every()` untuk jadwal sederhana berbasis interval. Ekspresinya berupa string apa pun yang kompatibel dengan PHP milik `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' );
```

## Penjadwalan Cron

Gunakan `cron()` untuk ekspresi cron standar dengan 5 bidang:

```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 * * * *' );
```

## Opsi jadwal

Builder `PendingSchedule` mendukung metode berikut:

| Metode | Deskripsi |
|---|---|
| `every( string $interval )` | Menetapkan ekspresi interval |
| `cron( string $expression )` | Menetapkan ekspresi cron |
| `on_queue( string $queue )` | Menetapkan antrean tujuan (default: `'default'`) |
| `overlap( OverlapPolicy $policy )` | Menetapkan kebijakan tumpang tindih (default: `Allow`) |

Anda harus memanggil `every()` atau `cron()` sebelum jadwal mengirim pekerjaan. Jika keduanya tidak ditetapkan, `RuntimeException` akan dilempar.

## Kebijakan tumpang tindih

Jika pekerjaan terjadwal masih berjalan (tertunda atau diproses) saat waktu tick berikutnya tiba, kebijakan tumpang tindih menentukan tindakan yang diambil. Atur dengan metode `overlap()`:

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

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

Enum `OverlapPolicy` memiliki tiga opsi:

| Kebijakan | Nilai | Perilaku |
|---|---|---|
| `OverlapPolicy::Allow` | `allow` | Selalu kirim pekerjaan baru, meskipun eksekusi sebelumnya masih aktif. Ini adalah default. |
| `OverlapPolicy::Skip` | `skip` | Lewati tick saat ini jika handler memiliki pekerjaan yang tertunda atau sedang diproses. `next_run` tetap diperbarui seperti biasa agar jadwal tetap sesuai irama. |
| `OverlapPolicy::Buffer` | `buffer` | Seperti Skip, tick tidak dikirim dan `next_run` maju ke jadwal rutin berikutnya. Berbeda dengan Skip, `last_run` tidak diperbarui. |

### Izinkan (default)

Beberapa instans handler yang sama dapat berjalan secara bersamaan. Gunakan ini untuk handler idempoten yang tidak bermasalah jika berjalan tumpang tindih.

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

### Lewati

Tick dilewati tanpa pemberitahuan jika handler masih berjalan. Gunakan ini untuk handler yang akan membuang sumber daya atau menimbulkan konflik jika instans kedua dijalankan.

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

### Buffer

Saat ini, perilakunya sama seperti Skip: ketika handler masih memiliki pekerjaan yang tertunda atau sedang diproses, tick tidak dikirim dan `next_run` berpindah ke jadwal rutin berikutnya. Satu-satunya perbedaan adalah Buffer membiarkan `last_run` tetap seperti semula, sedangkan Skip mencatat tick yang dilewati sebagai eksekusi terakhir.

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

## Cara kerjanya

Saat jadwal dibuat, Queuety menyimpannya di tabel `queuety_schedules` beserta ekspresi, handler, payload, dan waktu eksekusi berikutnya yang dihitung.

Pada setiap tick penjadwal (kira-kira sekali per menit di worker yang berjalan lama, atau saat Anda menjalankan `wp queuety schedule run`), penjadwal memeriksa jadwal yang `next_run`-nya telah lewat. Untuk setiap jadwal yang waktunya tiba, penjadwal mengirim pekerjaan baru dan memperbarui `next_run` ke jadwal berikutnya.

## Mengelola jadwal melalui 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
```

## Mengelola jadwal melalui 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();
```

## Payload

Jadwal dapat menyertakan payload statis yang diteruskan ke setiap pekerjaan yang dikirim:

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

Setiap kali jadwal berjalan, pekerjaan baru dikirim dengan payload ini.
