
# Guida introduttiva

## Installazione

### Requisiti

- PHP 8.2 o versioni successive e WordPress 6.4 o versioni successive
- MySQL 8.0+ o MariaDB 10.6+. I worker acquisiscono i job e gli schedule in scadenza con `SELECT ... FOR UPDATE SKIP LOCKED`, che i server meno recenti rifiutano con un errore di sintassi.
- `mysqli` o `pdo_mysql` (vedi sotto)
- WP-CLI sul server se esegui worker dedicati con `wp queuety work`
- Le estensioni `pcntl` e `posix` PHP se esegui pool di worker con `--workers` o `--min-workers`/`--max-workers`

Queuety richiede `mysqli` o `pdo_mysql` nel runtime PHP che carica WordPress e WP-CLI. Sceglie automaticamente il driver, preferendo `mysqli` nei runtime WordPress e mantenendo `pdo_mysql` disponibile per l’uso autonomo/diretto del runtime.

Per usare il runtime basato su DB senza il livello plugin WordPress, consulta [Uso autonomo](https://queuety.inline0.dev/it/docs/features/standalone-use). Questo approccio usa la stessa connessione e le stesse tabelle di runtime, ma non include i bridge degli hook WordPress né la registrazione WP-CLI.

### Dal file zip della release

Ogni [GitHubrelease](https://github.com/inline0/queuety/releases) include un file `queuety.zip`: il plugin con le dipendenze Composer già installate. Installate la versione più recente con WP-CLI:

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

Oppure scaricate il file zip e caricatelo da Plugin > Aggiungi nuovo > Carica plugin. È il metodo più semplice per un normale sito WordPress.

### Tramite Composer per Composer gestito da WordPress

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

Quindi attivate il plugin:

```bash
wp plugin activate queuety
```

Il tipo di pacchetto è `wordpress-plugin`. Composer lo colloca nella directory dei plugin solo se il progetto richiede `composer/installers` e associa quel tipo a un percorso di installazione, come fa Bedrock; inoltre, il progetto deve caricare il proprio `vendor/autoload.php` (anche Bedrock lo fa). Senza `composer/installers`, Composer lo installa in `vendor/queuety/queuety`, dove WordPress non lo trova: in una normale installazione WordPress, usate quindi il file zip della release.

### Dal codice sorgente durante lo sviluppo

Colloca il repository in `wp-content/plugins/queuety`, quindi installa le dipendenze PHP:

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

Al momento dell’attivazione, Queuety crea le tabelle del database (`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`), così i worker possono acquisire i job direttamente da MySQL.

Per impostazione predefinita, il plugin pianifica anche un worker eseguito una sola volta tramite WordPress cron ogni minuto per la coda `default`. Offre così una soluzione di base senza shell per job e workflow che rimangono su `default`, purché WordPress cron venga eseguito. Ogni esecuzione elabora al massimo un job e non attiva gli schedule ricorrenti, non recupera i job obsoleti né controlla le scadenze dei workflow; queste operazioni avvengono solo all’interno di un processo `wp queuety work` a lunga esecuzione ([#14](https://github.com/inline0/queuety/issues/14)). Per code personalizzate, schedule ricorrenti, latenza inferiore o carichi più pesanti, passate a processi `wp queuety work` dedicati.

## Configurazione

Tutte le costanti sono facoltative. Definiscile in `wp-config.php` prima del caricamento del plugin o prima dell’avvio di Queuety in un’installazione incorporata in un tema:

| Costante | Valore predefinito | Descrizione |
|---|---|---|
| `QUEUETY_RETENTION_DAYS` | `7` | Età predefinita in giorni per `wp queuety purge` e `Queuety::purge()`. Nessuna eliminazione automatica |
| `QUEUETY_LOG_RETENTION_DAYS` | `0` | Letta da `Config::log_retention_days()` ma non ancora usata; i log vengono conservati finché non chiami `Queuety::purge_logs()` ([#15](https://github.com/inline0/queuety/issues/15)) |
| `QUEUETY_MAX_EXECUTION_TIME` | `300` | Durata massima in secondi per job prima del timeout (non ancora applicata, vedi [Job](https://queuety.inline0.dev/it/docs/jobs#timeout)) |
| `QUEUETY_WORKER_SLEEP` | `1` | Secondi di attesa quando la coda è vuota |
| `QUEUETY_WORKER_MAX_JOBS` | `1000` | Numero massimo di job prima del riavvio del worker |
| `QUEUETY_WORKER_MAX_MEMORY` | `128` | MB massimi prima del riavvio del worker |
| `QUEUETY_RETRY_BACKOFF` | `exponential` | Strategia di backoff: `exponential`, `linear` o `fixed` |
| `QUEUETY_STALE_TIMEOUT` | `600` | Secondi prima del recupero dei job bloccati |
| `QUEUETY_CACHE_TTL` | `5` | TTL predefinito della cache in secondi |
| `QUEUETY_DEBUG` | `false` | Abilita la registrazione dettagliata dei worker |
| `QUEUETY_CLI_COMMAND` | `queuety` | Nome del comando radice WP-CLI |
| `QUEUETY_TABLE_PREFIX` | `queuety_` | Nome di base condiviso da tutte le tabelle Queuety dopo il prefisso DB WordPress |
| `QUEUETY_TABLE_JOBS` | `queuety_jobs` | Nome della tabella dei job |
| `QUEUETY_TABLE_WORKFLOWS` | `queuety_workflows` | Nome della tabella dei workflow |
| `QUEUETY_TABLE_LOGS` | `queuety_logs` | Nome della tabella dei log |
| `QUEUETY_TABLE_SCHEDULES` | `queuety_schedules` | Nome della tabella degli schedule |
| `QUEUETY_TABLE_SIGNALS` | `queuety_signals` | Nome della tabella dei segnali |
| `QUEUETY_TABLE_WORKFLOW_DEPENDENCIES` | `queuety_workflow_dependencies` | Nome della tabella delle attese per dipendenze dei workflow |
| `QUEUETY_TABLE_WORKFLOW_DISPATCH_KEYS` | `queuety_workflow_dispatch_keys` | Nome della tabella di idempotenza dei workflow durevoli |
| `QUEUETY_TABLE_CHUNKS` | `queuety_chunks` | Nome della tabella dei blocchi di dati in streaming |
| `QUEUETY_TABLE_QUEUE_STATES` | `queuety_queue_states` | Nome della tabella degli stati delle code |
| `QUEUETY_TABLE_WEBHOOKS` | `queuety_webhooks` | Nome della tabella dei webhook |
| `QUEUETY_TABLE_LOCKS` | `queuety_locks` | Nome della tabella dei blocchi |
| `QUEUETY_TABLE_BATCHES` | `queuety_batches` | Nome della tabella dei batch |
| `QUEUETY_TABLE_WORKFLOW_EVENTS` | `queuety_workflow_events` | Nome della tabella del log degli eventi dei workflow |
| `QUEUETY_TABLE_ARTIFACTS` | `queuety_artifacts` | Nome della tabella degli artefatti dei workflow |
| `QUEUETY_TABLE_STATE_MACHINES` | `queuety_state_machines` | Nome della tabella delle macchine a stati |
| `QUEUETY_TABLE_STATE_MACHINE_EVENTS` | `queuety_state_machine_events` | Nome della tabella del log degli eventi delle macchine a stati |
| `QUEUETY_DB_DRIVER` | `auto` | Driver MySQL: `auto`, `mysqli` o `pdo`. `auto` preferisce `mysqli` quando WordPress è caricato, altrimenti `pdo_mysql`, poi `mysqli` |

Le costanti per l’ammissione delle risorse e il pool adattivo (`QUEUETY_RESOURCE_*`, `QUEUETY_WORKER_POOL_*`) sono elencate nella pagina [Worker](https://queuety.inline0.dev/it/docs/features/workers).

`QUEUETY_TABLE_PREFIX` modifica solo la parte Queuety dei nomi delle tabelle. Il prefisso del database WordPress viene comunque anteposto al risultato, quindi `$wpdb->prefix = 'wp_'` e `QUEUETY_TABLE_PREFIX = 'themequeue_'` producono tabelle come `wp_themequeue_jobs`. Le costanti `QUEUETY_TABLE_*` esplicite hanno comunque la precedenza per le singole tabelle.

Le connessioni autonome possono anche impostare il prefisso delle tabelle Queuety per connessione:

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

In questo modo il prefisso del database WordPress resta intatto e cambia solo il segmento della tabella Queuety.

## Il tuo primo job

Crea una classe handler che implementi l’interfaccia `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,
        ];
    }
}
```

Registralo e invia il job:

```php
use Queuety\Queuety;

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

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

Oppure usa la moderna classe di job inviabile:

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

## Il tuo primo workflow

Definisci gli handler dei passaggi che implementano l’interfaccia `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 [];
    }
}
```

Avvia il workflow:

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

## Avvia un worker

```bash
wp queuety work
```

Il worker controlla la presenza di job in attesa, li esegue, fa avanzare i workflow e attende quando la coda è vuota. Premi `Ctrl+C` per fermarlo; il processo termina immediatamente, anche a metà di un job (vedi [Worker](https://queuety.inline0.dev/it/docs/features/workers#worker-lifecycle)).

La `SendEmailHandler` invia i job alla coda `emails` tramite `config()`, quindi un worker su `default` non li acquisisce. Indica tutte le code che usi:

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

Se non esegui un worker dedicato, Queuety dispone comunque della soluzione di ripiego predefinita WordPress cron, eseguita una volta al minuto e descritta sopra, limitata alla coda `default` e a un job per esecuzione. Il worker dedicato offre maggiore capacità di elaborazione e minore latenza.

Per la produzione, esegui più worker:

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

Elabora più code con ordinamento per priorità:

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

## Cosa fare dopo

- [Job](https://queuety.inline0.dev/it/docs/jobs) per la guida completa all’invio e alla gestione degli handler
- [Workflow](https://queuety.inline0.dev/it/docs/workflows) per catene, passaggi paralleli, diramazioni condizionali e workflow annidati
- [Middleware](https://queuety.inline0.dev/it/docs/features/middleware) per limitazione della frequenza, regolazione del carico e logica personalizzata delle pipeline
- [Elaborazione in batch](https://queuety.inline0.dev/it/docs/features/batching) per inviare gruppi di job con callback
- [Passaggi in streaming](https://queuety.inline0.dev/it/docs/workflows/streaming) per salvare i dati trasmessi un blocco alla volta
- [Pianificazione](https://queuety.inline0.dev/it/docs/features/scheduling) per i job ricorrenti
- [Caching](https://queuety.inline0.dev/it/docs/features/caching) per il livello di cache collegabile
- [Test](https://queuety.inline0.dev/it/docs/features/testing) per QueueFake e le asserzioni dei test
- [CLI Riferimento](https://queuety.inline0.dev/it/docs/cli) per tutti i comandi disponibili
- [PHP API](https://queuety.inline0.dev/it/docs/api) per l’accesso programmatico
