
# Planowanie zadań

Queuety ma wbudowaną obsługę zadań cyklicznych. Zamiast polegać na `wp_cron`, harmonogramy są zapisywane w bazie danych i oceniane mniej więcej raz na minutę przez długotrwały proces `wp queuety work` (lub proces nadrzędny puli workerów). `wp queuety work --once`, `wp queuety flush` ani wbudowany mechanizm awaryjny wtyczki WP-Cron nie oceniają harmonogramów ([#14](https://github.com/inline0/queuety/issues/14)); bez długotrwałego workera uruchom samodzielnie `wp queuety schedule run`.

## Planowanie interwałowe

Użyj `every()` do prostych harmonogramów opartych na interwałach. Wyrażenie może być dowolnym ciągiem zgodnym z 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' );
```

## Planowanie Cron

Użyj `cron()` do standardowych wyrażeń cron z 5 polami:

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

## Opcje harmonogramu

Konstruktor `PendingSchedule` obsługuje następujące metody:

| Metoda | Opis |
|---|---|
| `every( string $interval )` | Ustaw wyrażenie interwału |
| `cron( string $expression )` | Ustaw wyrażenie cron |
| `on_queue( string $queue )` | Ustaw docelową kolejkę (domyślnie: `'default'`) |
| `overlap( OverlapPolicy $policy )` | Ustaw zasady nakładania się (domyślnie: `Allow`) |

Przed uruchomieniem harmonogramu musisz wywołać `every()` lub `cron()`. Jeśli nie ustawiono żadnej z tych metod, zostanie zgłoszony `RuntimeException`.

## Zasady nakładania się zadań

Jeśli w chwili kolejnego wyzwolenia harmonogramu zaplanowane zadanie nadal działa (oczekuje lub jest przetwarzane), zasady nakładania się określają dalsze postępowanie. Ustaw je metodą `overlap()`:

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

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

Enum `OverlapPolicy` ma trzy warianty:

| Zasada | Wartość | Działanie |
|---|---|---|
| `OverlapPolicy::Allow` | `allow` | Zawsze uruchamiaj nowe zadanie, nawet jeśli poprzedni przebieg nadal trwa. To ustawienie domyślne. |
| `OverlapPolicy::Skip` | `skip` | Pomiń bieżący takt, jeśli dla handlera są zadania oczekujące lub przetwarzane. `next_run` jest normalnie aktualizowane, więc harmonogram zachowuje regularny rytm. |
| `OverlapPolicy::Buffer` | `buffer` | Podobnie jak w przypadku Skip, takt nie jest uruchamiany, a `next_run` przesuwa się do kolejnego regularnego wystąpienia. W przeciwieństwie do Skip, `last_run` nie jest aktualizowane. |

### Allow (domyślnie)

Wiele instancji tego samego handlera może działać równolegle. Używaj tej opcji dla handlerów idempotentnych, w przypadku których nakładanie się nie powoduje problemów.

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

### Skip

Takt jest po cichu pomijany, jeśli handler nadal działa. Używaj tej opcji dla handlerów, w których uruchomienie drugiej instancji byłoby niepotrzebne lub powodowałoby konflikty.

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

### Buffer

Obecnie działa tak samo jak Skip: gdy handler ma zadanie oczekujące lub przetwarzane, takt nie jest uruchamiany, a `next_run` przesuwa się do kolejnego regularnego wystąpienia. Jedyna różnica polega na tym, że Buffer pozostawia `last_run` bez zmian, natomiast Skip zapisuje pominięty takt jako ostatnie uruchomienie.

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

## Jak to działa

Podczas tworzenia harmonogramu Queuety zapisuje go w tabeli `queuety_schedules` wraz z wyrażeniem, handlerem, ładunkiem i obliczonym terminem następnego uruchomienia.

Przy każdym takcie harmonogramu (mniej więcej raz na minutę w długotrwałym workerze lub po uruchomieniu `wp queuety schedule run`) scheduler sprawdza, czy minął termin `next_run` któregoś harmonogramu. Dla każdego harmonogramu, którego termin nadszedł, uruchamia nowe zadanie i aktualizuje `next_run`, ustawiając kolejne wystąpienie.

## Zarządzanie harmonogramami przez 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
```

## Zarządzanie harmonogramami przez 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();
```

## Ładunek

Harmonogramy mogą zawierać statyczny ładunek przekazywany do każdego uruchomionego zadania:

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

Za każdym razem, gdy harmonogram zostanie uruchomiony, powstanie nowe zadanie z tym ładunkiem.
