
# Memulai

## Instalasi

### Persyaratan

- PHP 8.2 atau lebih baru dan WordPress 6.4 atau lebih baru
- MySQL 8.0+ atau MariaDB 10.6+. Worker mengambil job dan jadwal yang jatuh tempo dengan `SELECT ... FOR UPDATE SKIP LOCKED`, yang ditolak server lama dengan kesalahan sintaks.
- `mysqli` atau `pdo_mysql` (lihat di bawah)
- WP-CLI di server jika Anda menjalankan worker khusus dengan `wp queuety work`
- Ekstensi `pcntl` dan `posix` PHP jika Anda menjalankan kumpulan worker dengan `--workers` atau `--min-workers`/`--max-workers`

Queuety memerlukan `mysqli` atau `pdo_mysql` dalam runtime PHP yang memuat WordPress dan WP-CLI. Driver dipilih secara otomatis: `mysqli` diutamakan untuk runtime WordPress, sementara `pdo_mysql` tetap tersedia untuk penggunaan runtime mandiri/langsung.

Jika Anda menginginkan runtime berbasis DB tanpa lapisan plugin WordPress, lihat [Penggunaan Mandiri](https://queuety.inline0.dev/id/docs/features/standalone-use). Cara ini menggunakan koneksi dan tabel runtime yang sama, tetapi tidak menyertakan bridge hook WordPress atau pendaftaran WP-CLI.

### Dari file zip rilis

Setiap [rilis](https://github.com/inline0/queuety/releases) GitHub memiliki aset `queuety.zip`: plugin dengan dependensi Composer-nya sudah terpasang. Instal versi terbaru dengan WP-CLI:

```bash
wp plugin install https://github.com/inline0/queuety/releases/latest/download/queuety.zip --activate
```

Atau unduh file zip dan unggah di Plugins > Add New > Upload Plugin. Ini cara paling sederhana untuk situs WordPress biasa.

### Melalui Composer untuk Composer yang dikelola WordPress

```bash
composer require queuety/queuety
```

Lalu aktifkan plugin:

```bash
wp plugin activate queuety
```

Jenis paketnya adalah `wordpress-plugin`. Composer menempatkannya di direktori plugin hanya jika proyek memerlukan `composer/installers` dan memetakan jenis tersebut ke jalur penginstal, seperti yang dilakukan Bedrock, dan proyek harus memuat `vendor/autoload.php`-nya sendiri (Bedrock juga melakukannya). Tanpa `composer/installers`, Composer memasangnya ke `vendor/queuety/queuety`, tempat WordPress tidak dapat menemukannya, jadi gunakan file zip rilis pada instalasi WordPress biasa.

### Dari kode sumber selama pengembangan

Tempatkan repositori di `wp-content/plugins/queuety`, lalu instal dependensi PHP:

```bash
composer install
wp plugin activate queuety
```

Saat diaktifkan, Queuety membuat tabel databasenya (`queuety_jobs`, `queuety_workflows`, `queuety_logs`, `queuety_schedules`, `queuety_queue_states`, `queuety_webhooks`, `queuety_locks`, `queuety_signals`, `queuety_workflow_dependencies`, `queuety_workflow_dispatch_keys`, `queuety_batches`, `queuety_chunks`, `queuety_workflow_events`, `queuety_artifacts`, `queuety_state_machines`, `queuety_state_machine_events`) agar worker dapat mengambil job langsung dari MySQL.

Secara default, plugin juga menjadwalkan worker sekali jalan melalui WordPress cron setiap menit untuk antrean `default`. Ini menyediakan opsi dasar tanpa shell untuk job dan workflow yang tetap berjalan di `default`, selama WordPress cron terpicu. Setiap eksekusi memproses paling banyak satu job, dan tidak memicu jadwal berulang, memulihkan job usang, atau memeriksa tenggat workflow; semua itu hanya berjalan di dalam proses `wp queuety work` yang berjalan lama ([#14](https://github.com/inline0/queuety/issues/14)). Untuk antrean khusus, jadwal berulang, latensi lebih rendah, atau beban kerja lebih berat, gunakan proses `wp queuety work` khusus.

## Konfigurasi

Semua konstanta bersifat opsional. Definisikan di `wp-config.php` sebelum plugin dimuat, atau sebelum Queuety dimulai pada instalasi bergaya tema tersemat:

| Konstanta | Nilai bawaan | Deskripsi |
|---|---|---|
| `QUEUETY_RETENTION_DAYS` | `7` | Usia bawaan dalam hari untuk `wp queuety purge` dan `Queuety::purge()`. Tidak ada yang dihapus otomatis |
| `QUEUETY_LOG_RETENTION_DAYS` | `0` | Dibaca oleh `Config::log_retention_days()` tetapi belum digunakan; log disimpan sampai Anda memanggil `Queuety::purge_logs()` ([#15](https://github.com/inline0/queuety/issues/15)) |
| `QUEUETY_MAX_EXECUTION_TIME` | `300` | Detik maksimum per job sebelum waktu habis (belum diterapkan, lihat [Job](https://queuety.inline0.dev/id/docs/jobs#timeout)) |
| `QUEUETY_WORKER_SLEEP` | `1` | Detik jeda saat antrean kosong |
| `QUEUETY_WORKER_MAX_JOBS` | `1000` | Jumlah job maksimum sebelum worker dimulai ulang |
| `QUEUETY_WORKER_MAX_MEMORY` | `128` | MB maksimum sebelum worker dimulai ulang |
| `QUEUETY_RETRY_BACKOFF` | `exponential` | Strategi jeda bertahap: `exponential`, `linear`, atau `fixed` |
| `QUEUETY_STALE_TIMEOUT` | `600` | Detik sebelum job yang macet dipulihkan |
| `QUEUETY_CACHE_TTL` | `5` | TTL cache bawaan dalam detik |
| `QUEUETY_DEBUG` | `false` | Aktifkan pencatatan log worker yang terperinci |
| `QUEUETY_CLI_COMMAND` | `queuety` | Nama perintah WP-CLI tingkat akar |
| `QUEUETY_TABLE_PREFIX` | `queuety_` | Nama dasar bersama untuk semua tabel Queuety setelah prefiks DB WordPress |
| `QUEUETY_TABLE_JOBS` | `queuety_jobs` | Nama tabel job |
| `QUEUETY_TABLE_WORKFLOWS` | `queuety_workflows` | Nama tabel workflow |
| `QUEUETY_TABLE_LOGS` | `queuety_logs` | Nama tabel log |
| `QUEUETY_TABLE_SCHEDULES` | `queuety_schedules` | Nama tabel jadwal |
| `QUEUETY_TABLE_SIGNALS` | `queuety_signals` | Nama tabel sinyal |
| `QUEUETY_TABLE_WORKFLOW_DEPENDENCIES` | `queuety_workflow_dependencies` | Nama tabel tunggu dependensi workflow |
| `QUEUETY_TABLE_WORKFLOW_DISPATCH_KEYS` | `queuety_workflow_dispatch_keys` | Nama tabel idempotensi workflow persisten |
| `QUEUETY_TABLE_CHUNKS` | `queuety_chunks` | Nama tabel potongan streaming |
| `QUEUETY_TABLE_QUEUE_STATES` | `queuety_queue_states` | Nama tabel status antrean |
| `QUEUETY_TABLE_WEBHOOKS` | `queuety_webhooks` | Nama tabel webhook |
| `QUEUETY_TABLE_LOCKS` | `queuety_locks` | Nama tabel lock |
| `QUEUETY_TABLE_BATCHES` | `queuety_batches` | Nama tabel batch |
| `QUEUETY_TABLE_WORKFLOW_EVENTS` | `queuety_workflow_events` | Nama tabel log event workflow |
| `QUEUETY_TABLE_ARTIFACTS` | `queuety_artifacts` | Nama tabel artefak workflow |
| `QUEUETY_TABLE_STATE_MACHINES` | `queuety_state_machines` | Nama tabel mesin status |
| `QUEUETY_TABLE_STATE_MACHINE_EVENTS` | `queuety_state_machine_events` | Nama tabel log event mesin status |
| `QUEUETY_DB_DRIVER` | `auto` | Driver MySQL: `auto`, `mysqli`, atau `pdo`. `auto` mengutamakan `mysqli` saat WordPress dimuat, jika tidak `pdo_mysql`, lalu `mysqli` |

Konstanta penerimaan sumber daya dan kumpulan adaptif (`QUEUETY_RESOURCE_*`, `QUEUETY_WORKER_POOL_*`) tercantum di halaman [Worker](https://queuety.inline0.dev/id/docs/features/workers).

`QUEUETY_TABLE_PREFIX` hanya mengubah bagian Queuety pada nama tabel. Prefiks database WordPress tetap membungkus hasilnya, sehingga `$wpdb->prefix = 'wp_'` dan `QUEUETY_TABLE_PREFIX = 'themequeue_'` menghasilkan tabel seperti `wp_themequeue_jobs`. Konstanta `QUEUETY_TABLE_*` eksplisit tetap diutamakan untuk masing-masing tabel.

Koneksi mandiri juga dapat menetapkan prefiks tabel Queuety per koneksi:

```php
$conn = new Connection(
    host: '127.0.0.1:3306',
    dbname: 'wordpress',
    user: 'root',
    password: 'secret',
    prefix: 'wp_',
    table_prefix: 'themequeue_',
);
```

Itu mempertahankan prefiks database WordPress dan hanya mengubah segmen tabel Queuety.

## Job pertama Anda

Buat kelas handler yang mengimplementasikan antarmuka `Handler`:

```php
use Queuety\Handler;

class SendEmailHandler implements Handler {
    public function handle( array $payload ): void {
        wp_mail( $payload['to'], $payload['subject'], $payload['body'] );
    }

    public function config(): array {
        return [
            'queue'           => 'emails',
            'max_attempts'    => 5,
        ];
    }
}
```

Daftarkan lalu kirim untuk dijalankan:

```php
use Queuety\Queuety;

Queuety::register( 'send_email', SendEmailHandler::class );

Queuety::dispatch( 'send_email', [
    'to'      => 'user@example.com',
    'subject' => 'Welcome',
    'body'    => 'Hello from Queuety!',
] );
```

Atau gunakan kelas job modern yang dapat dikirim:

```php
use Queuety\Contracts\Job;
use Queuety\Dispatchable;

readonly class SendEmailJob implements Job {
    use Dispatchable;

    public function __construct(
        public string $to,
        public string $subject,
        public string $body,
    ) {}

    public function handle(): void {
        wp_mail( $this->to, $this->subject, $this->body );
    }
}

SendEmailJob::dispatch( 'user@example.com', 'Welcome', 'Hello from Queuety!' );
```

## Workflow pertama Anda

Definisikan handler langkah yang mengimplementasikan antarmuka `Step`:

```php
use Queuety\Step;

class FetchDataHandler implements Step {
    public function handle( array $state ): array {
        $user = get_user_by( 'ID', $state['user_id'] );
        return [ 'user_name' => $user->display_name ];
    }

    public function config(): array {
        return [];
    }
}

class CallLLMHandler implements Step {
    public function handle( array $state ): array {
        $response = wp_remote_post( 'https://api.openai.com/v1/chat/completions', [
            'body' => json_encode( [ 'prompt' => "Generate report for {$state['user_name']}" ] ),
        ] );
        return [ 'llm_response' => wp_remote_retrieve_body( $response ) ];
    }

    public function config(): array {
        return [ 'max_attempts' => 5 ];
    }
}

class FormatOutputHandler implements Step {
    public function handle( array $state ): array {
        $url = save_report( $state['user_name'], $state['llm_response'] );
        return [ 'report_url' => $url ];
    }

    public function config(): array {
        return [];
    }
}
```

Kirim workflow untuk dijalankan:

```php
$workflow_id = Queuety::workflow( 'generate_report' )
    ->then( FetchDataHandler::class )
    ->then( CallLLMHandler::class )
    ->then( FormatOutputHandler::class )
    ->dispatch( [ 'user_id' => 42 ] );
```

## Mulai worker

```bash
wp queuety work
```

Worker memeriksa job yang menunggu, menjalankannya, melanjutkan workflow, dan beristirahat saat antrean kosong. Tekan `Ctrl+C` untuk berhenti; proses akan langsung berakhir, bahkan di tengah job (lihat [Worker](https://queuety.inline0.dev/id/docs/features/workers#worker-lifecycle)).

`SendEmailHandler` di atas mengirim job-nya ke antrean `emails` melalui `config()`, jadi worker di `default` tidak akan mengambilnya. Sebutkan setiap antrean yang Anda gunakan:

```bash
wp queuety work --queue=emails,default
```

Jika Anda tidak menjalankan worker khusus, Queuety tetap memiliki opsi cadangan WordPress cron bawaan yang berjalan sekali per menit seperti dijelaskan di atas, terbatas pada antrean `default` dan satu job per eksekusi. Worker khusus menawarkan throughput lebih tinggi dan latensi lebih rendah.

Untuk penggunaan produksi, jalankan beberapa worker:

```bash
wp queuety work --workers=4
```

Proses beberapa antrean dengan urutan prioritas:

```bash
wp queuety work --queue=high,default,low
```

## Langkah berikutnya

- [Job](https://queuety.inline0.dev/id/docs/jobs) untuk panduan lengkap pengiriman dan handler
- [Workflow](https://queuety.inline0.dev/id/docs/workflows) untuk rantai, langkah paralel, percabangan bersyarat, dan menjalankan workflow
- [Middleware](https://queuety.inline0.dev/id/docs/features/middleware) untuk pembatasan laju, pengaturan throttle, dan logika pipeline khusus
- [Batching](https://queuety.inline0.dev/id/docs/features/batching) untuk mengirim kelompok job dengan callback
- [Langkah Streaming](https://queuety.inline0.dev/id/docs/workflows/streaming) untuk menyimpan data streaming sedikit demi sedikit
- [Penjadwalan](https://queuety.inline0.dev/id/docs/features/scheduling) untuk job berulang
- [Caching](https://queuety.inline0.dev/id/docs/features/caching) untuk lapisan cache yang dapat diganti
- [Pengujian](https://queuety.inline0.dev/id/docs/features/testing) untuk QueueFake dan asersi pengujian
- [CLI Referensi](https://queuety.inline0.dev/id/docs/cli) untuk semua perintah yang tersedia
- [PHP API](https://queuety.inline0.dev/id/docs/api) untuk akses melalui kode
