
# Planificare

Queuety oferă suport integrat pentru joburi recurente. În loc să se bazeze pe `wp_cron`, programările sunt stocate în baza de date și evaluate aproximativ o dată pe minut de un proces `wp queuety work` cu execuție îndelungată (sau de procesul părinte al unui grup de workeri). `wp queuety work --once`, `wp queuety flush` și mecanismul de rezervă integrat al pluginului WP-Cron nu evaluează programările ([#14](https://github.com/inline0/queuety/issues/14)); în lipsa unui worker cu execuție îndelungată, rulați chiar dumneavoastră `wp queuety schedule run`.

## Planificare pe intervale

Folosiți `every()` pentru programări simple, bazate pe intervale. Expresia poate fi orice șir compatibil cu PHP și cu `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' );
```

## Planificare Cron

Folosiți `cron()` pentru expresii cron standard cu 5 câmpuri:

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

## Opțiuni de programare

Constructorul `PendingSchedule` acceptă următoarele metode:

| Metodă | Descriere |
|---|---|
| `every( string $interval )` | Setează o expresie de interval |
| `cron( string $expression )` | Setează o expresie cron |
| `on_queue( string $queue )` | Setează coada țintă (implicit: `'default'`) |
| `overlap( OverlapPolicy $policy )` | Setează politica de suprapunere (implicit: `Allow`) |

Trebuie să apelați fie `every()`, fie `cron()` înainte ca programarea să trimită jobul. Dacă nu setați niciuna, se va arunca o `RuntimeException`.

## Politici de suprapunere

Când un job programat încă rulează (în așteptare sau în procesare) în momentul declanșării următorului ciclu, politica de suprapunere determină ce se întâmplă. Setați-o cu metoda `overlap()`:

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

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

Enumul `OverlapPolicy` are trei opțiuni:

| Politică | Valoare | Comportament |
|---|---|---|
| `OverlapPolicy::Allow` | `allow` | Trimite întotdeauna un job nou, chiar dacă execuția anterioară este încă activă. Aceasta este opțiunea implicită. |
| `OverlapPolicy::Skip` | `skip` | Omite ciclul curent dacă handlerul are joburi în așteptare sau în procesare. `next_run` se actualizează normal, astfel încât programarea să își păstreze ritmul. |
| `OverlapPolicy::Buffer` | `buffer` | La fel ca pentru Skip, ciclul nu este trimis, iar `next_run` avansează la următoarea apariție regulată. Spre deosebire de Skip, `last_run` nu se actualizează. |

### Allow (implicit)

Mai multe instanțe ale aceluiași handler pot rula simultan. Folosiți această opțiune pentru handlere idempotente, pentru care suprapunerea nu creează probleme.

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

### Skip

Ciclul este omis fără notificare dacă handlerul încă rulează. Folosiți această opțiune pentru handlere la care o a doua instanță ar consuma resurse inutil sau ar provoca conflicte.

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

### Buffer

În prezent, funcționează la fel ca Skip: când handlerul are încă un job în așteptare sau în procesare, ciclul nu este trimis, iar `next_run` trece la următoarea apariție regulată. Singura diferență este că Buffer lasă `last_run` neschimbat, în timp ce Skip înregistrează ciclul omis drept ultima execuție.

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

## Cum funcționează

La crearea unei programări, Queuety o stochează în tabelul `queuety_schedules` împreună cu expresia, handlerul, payloadul și următoarea oră de execuție calculată.

La fiecare ciclu al planificatorului (aproximativ o dată pe minut într-un worker cu execuție îndelungată sau când rulați `wp queuety schedule run`), planificatorul verifică programările pentru care termenul `next_run` a trecut. Pentru fiecare programare scadentă, trimite un job nou și actualizează `next_run` la următoarea apariție.

## Gestionarea programărilor prin 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
```

## Gestionarea programărilor prin 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

Programările pot include un payload static, transmis fiecărui job trimis:

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

De fiecare dată când se declanșează programarea, este trimis un job nou cu acest payload.
