
# PHP API

Alt i Queuety er tilgængeligt via den statiske klasse `Queuety\Queuety`. Den er det eneste indgangspunkt til at udsende jobs, opbygge workflows, styre tilstandsmaskiner, administrere køer og få adgang til interne undersystemer.

```php
use Queuety\Queuety;
```

## Selvstændig adgang til kernen

Queuetys DB-baserede runtime kan initialiseres uden for WordPress.

Denne selvstændige mulighed er beregnet til orkestreringskernen:

- jobs og workers (worker-pools kræver også konstanterne `DB_HOST`, `DB_NAME`, `DB_USER` og `DB_PASSWORD`, se nedenfor)
- workflows og signaler
- tilstandsmaskiner og hændelser
- artefakter, logfiler, målinger og tidsplaner

Det er ikke en erstatning for adapteren WordPress. `Queuety::on_action()`,
`replace_wp_cron()`, plugin-opstarten og den egentlige registreringssti for `wp queuety ...`
kræver stadig WordPress.

### `Queuety::init( Connection $conn )`

Initialisér Queuety med en direkte DB-baseret forbindelse.

```php
use Queuety\Connection;
use Queuety\Queuety;

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

Queuety::init( $conn );
```

Det valgfrie argument `table_prefix` ændrer runtime-tabellernes Queuety-del pr. forbindelse:

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

Dermed opløses tabeller som `queuety_jobs` til `wp_themequeue_jobs`.

### `Queuety::ensure_schema()`

Sørg for, at runtime-tabellerne Queuety findes for den aktive forbindelse.

```php
Queuety::init( $conn );
Queuety::ensure_schema();
```

Se [Selvstændig brug](https://queuety.inline0.dev/da/docs/features/standalone-use) for hele modellen og WordPress-grænsen.

## Jobs

### `Queuety::dispatch( $handler, $payload )`

Udsend et job. Accepterer enten en streng med et handlernavn eller en instans af `Contracts\Job`. Returnerer en `PendingJob`-builder til kædning af indstillinger.

```php
// Handler name + payload (original API)
Queuety::dispatch( 'send_email', [ 'to' => 'user@example.com' ] );

// Contracts\Job instance (v0.6.0+)
Queuety::dispatch( new SendEmailJob( to: 'user@example.com' ) );

// With options
Queuety::dispatch( 'send_email', [ 'to' => 'user@example.com' ] )
    ->on_queue( 'emails' )
    ->with_priority( Priority::High )
    ->delay( 300 )
    ->max_attempts( 5 )
    ->rate_limit( 10, 60 )
    ->unique()
    ->after( $other_job_id );

// Get the job ID
$job_id = Queuety::dispatch( 'send_email', $payload )->id();
```

Når der angives en instans af `Contracts\Job`, udtrækker serializeren FQCN som handlernavn og offentlige egenskaber som payload. Parameteren `$payload` ignoreres, når `$handler` er en instans af `Job`.

### `PendingJob`-metoder

| Metode | Beskrivelse |
|---|---|
| `on_queue( string $queue )` | Angiv målkøen |
| `with_priority( Priority $priority )` | Angiv prioritetsniveauet |
| `delay( int $seconds )` | Forsinkelse, før jobbet bliver tilgængeligt |
| `max_attempts( int $max )` | Maksimalt antal genforsøg |
| `rate_limit( int $max, int $window )` | Hastighedsgrænse: maksimalt antal kørsler pr. tidsvindue i sekunder |
| `unique()` | Forhindr dobbelte udsendelser |
| `after( int $job_id )` | Vent på, at et andet job fuldføres først |
| `concurrency_group( string $group, int $limit )` | Placer jobbet i en fælles worker-admissionsgruppe |
| `cost_units( int $units )` | Tilknyt metadata om relativ kørselsomkostning til udsendelsen |
| `id()` | Gennemtving udsendelse, og returnér job-id'et |

`concurrency_group()` og `cost_units()` indgår i den bredere model for [ressourcehåndtering](https://queuety.inline0.dev/da/docs/features/resource-management), så den samme udsendelse kan indgå i samtidighedsgrænser baseret på antal, vægtede budgetter for køer eller udbydere og heuristikker for worker-admission.

### `Queuety::dispatch_sync( $handler, $payload )`

Kør et job synkront i den aktuelle proces uden at føje det til køen.

```php
// With a Job instance
Queuety::dispatch_sync( new SendEmailJob( to: 'user@example.com', subject: 'Hi', body: 'Hello' ) );

// With a handler name and payload
Queuety::dispatch_sync( 'send_email', [ 'to' => 'user@example.com' ] );
```

Jobbets metode `handle()` kaldes direkte. Der oprettes ingen databaserække, ingen worker involveres, og middleware anvendes ikke.

### `Queuety::batch( $jobs )`

Udsend flere jobs i én INSERT med flere rækker.

```php
$job_ids = Queuety::batch( [
    [ 'handler' => 'send_email', 'payload' => [ 'to' => 'a@example.com' ], 'queue' => 'emails' ],
    [ 'handler' => 'send_email', 'payload' => [ 'to' => 'b@example.com' ], 'priority' => 2 ],
] );
```

### `Queuety::create_batch( $jobs )`

Opret en `BatchBuilder` til udsendelse af en gruppe jobs med tilbagekald og statussporing. Se [Batchkørsel](https://queuety.inline0.dev/da/docs/features/batching) for alle detaljer.

```php
$batch = Queuety::create_batch( [
    new ImportUsersJob( $chunk_1 ),
    new ImportUsersJob( $chunk_2 ),
] )
    ->name( 'Import users' )
    ->then( ImportCompleteHandler::class )
    ->catch( ImportFailedHandler::class )
    ->finally( ImportCleanupHandler::class )
    ->allow_failures()
    ->on_queue( 'imports' )
    ->dispatch();
```

### Metoder for `BatchBuilder`

| Metode | Returnerer | Beskrivelse |
|---|---|---|
| `name( string $name )` | `self` | Angiv et navn for batchen |
| `on_queue( string $queue )` | `self` | Angiv køen for alle jobs i batchen |
| `then( string $handler_class )` | `self` | Handler, der kaldes, når batchen gennemføres uden fejl |
| `catch( string $handler_class )` | `self` | Handler, der kaldes, når det første job i batchen fejler |
| `finally( string $handler_class )` | `self` | Handler, der kaldes, når batchen afsluttes (med eller uden fejl) |
| `allow_failures()` | `self` | Tillad, at tilbagekaldet `then` udføres, også når der opstår fejl |
| `dispatch()` | `Batch` | Opret batchrækken og alle jobs, og returnér værdiobjektet `Batch` |

### `Queuety::find_batch( $id )`

Find en batch efter id. Returnerer et værdiobjekt af typen `Batch` eller `null`.

```php
$batch = Queuety::find_batch( $batch_id );

if ( null !== $batch ) {
    echo $batch->progress() . '% complete';
}
```

## Worker-styring

### `Queuety::run_worker( $queue = 'default', $once = false )`

Kør ét worker-loop direkte.

```php
Queuety::run_worker( 'default' );
Queuety::run_worker( 'critical,default', true );
```

### `Queuety::run_worker_pool( $workers, $queue = 'default' )`

Kør en worker-pool med fast størrelse direkte. Kræver udvidelserne `pcntl` og `posix`. Poolen læser konstanterne WordPress `DB_HOST`, `DB_NAME`, `DB_USER` og `DB_PASSWORD` til sine underordnede forbindelser (kun tabelpræfikserne kommer fra den initialiserede forbindelse), så definér dem, når du kører en pool uden for WordPress ([#5](https://github.com/inline0/queuety/issues/5)).

```php
Queuety::run_worker_pool( 4, 'providers' );
```

### `Queuety::run_auto_scaling_worker_pool( $min_workers, $max_workers, $queue = 'default' )`

Kør en adaptiv worker-pool direkte. Samme krav som for `run_worker_pool()`.

```php
Queuety::run_auto_scaling_worker_pool( 2, 6, 'providers' );
```

### `Batch`-værdiobjekt

| Metode/egenskab | Type | Beskrivelse |
|---|---|---|
| `$id` | `int` | Batch-id |
| `$name` | `string\|null` | Valgfrit batchnavn |
| `$total_jobs` | `int` | Samlet antal job i batchen |
| `$pending_jobs` | `int` | Job, der stadig afventer |
| `$failed_jobs` | `int` | Antal mislykkede job |
| `$failed_job_ids` | `array` | Id'er på mislykkede job |
| `$created_at` | `DateTimeImmutable` | Hvornår batchen blev oprettet |
| `$finished_at` | `DateTimeImmutable\|null` | Hvornår batchen blev færdig |
| `$cancelled_at` | `DateTimeImmutable\|null` | Hvornår batchen blev annulleret |
| `progress()` | `int` | Fuldførelsesprocent (0-100) |
| `finished()` | `bool` | Om batchen er færdig |
| `has_failures()` | `bool` | Om et job mislykkedes |
| `cancelled()` | `bool` | Om batchen blev annulleret |

### `Queuety::chain( $jobs )`

Opret en `ChainBuilder` til sekventiel jobafvikling. Hvert job afhænger af, at det foregående fuldføres uden fejl.

```php
$first_job_id = Queuety::chain( [
    new FetchDataJob( $url ),
    new ProcessDataJob(),
    new NotifyCompleteJob(),
] )
    ->on_queue( 'pipeline' )
    ->catch( ChainFailedHandler::class )
    ->dispatch();
```

### `ChainBuilder`-metoder

| Metode | Returnerer | Beskrivelse |
|---|---|---|
| `on_queue( string $queue )` | `self` | Angiv køen for alle job i kæden |
| `catch( string $handler_class )` | `self` | Handler, der kaldes, når et job i kæden begraves permanent |
| `dispatch()` | `int` | Opret alle job med sekventielle afhængigheder; returnerer det første job-id |

### `Queuety::retry( $job_id )`

Prøv et bestemt job igen. Nulstiller det til status `pending`.

```php
Queuety::retry( 42 );
```

### `Queuety::retry_buried()`

Prøv alle begravede job igen. Returnerer antallet af job, der blev forsøgt igen.

```php
$count = Queuety::retry_buried();
```

### `Queuety::purge( $older_than_days )`

Slet fuldførte job. Returnerer antallet af slettede job.

```php
$count = Queuety::purge();     // uses QUEUETY_RETENTION_DAYS
$count = Queuety::purge( 30 ); // purge jobs older than 30 days
```

## Køer

### `Queuety::stats( $queue )`

Hent jobantal grupperet efter status.

```php
$stats = Queuety::stats();          // all queues
$stats = Queuety::stats( 'emails' ); // specific queue
// ['pending' => 12, 'processing' => 3, 'completed' => 150, 'failed' => 2, 'buried' => 1]
```

### `Queuety::buried( $queue )`

Hent alle begravede job.

```php
$jobs = Queuety::buried();
$jobs = Queuety::buried( 'emails' );
```

### `Queuety::pause( $queue )`

Sæt en kø på pause, så workers springer den over.

```php
Queuety::pause( 'emails' );
```

### `Queuety::resume( $queue )`

Genoptag en kø, der er sat på pause.

```php
Queuety::resume( 'emails' );
```

### `Queuety::is_paused( $queue )`

Kontrollér, om en kø er sat på pause.

```php
if ( Queuety::is_paused( 'emails' ) ) {
    // Queue is paused
}
```

## Workflows

### `Queuety::workflow( $name )`

Begynd at opbygge et workflow. Returnerer en `WorkflowBuilder`.

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

### `WorkflowBuilder`-metoder

| Metode | Beskrivelse |
|---|---|
| `then( string $handler_class, ?string $name = null )` | Tilføj et sekventielt trin. Valgfrit navn til betinget forgrening. |
| `parallel( array $handler_classes )` | Tilføj en gruppe af parallelle trin. |
| `for_each( string $items_key, string $handler_class, ?string $result_key = null, ForEachMode $mode = ForEachMode::All, ?int $quorum = null, ?string $reducer_class = null, ?string $name = null )` | Tilføj et dynamisk for-each-trin, der udvider sig til ét forgreningsjob pr. element i workflowtilstanden. |
| `repeat_while( string $target_step, ?string $state_key = null, mixed $expected = true, ?string $name = null, ?string $condition_class = null, ?int $max_iterations = null )` | Gå tilbage til et tidligere navngivet trin, mens en offentlig tilstandsnøgle eller `RepeatCondition`-klasse matcher. |
| `repeat_until( string $target_step, ?string $state_key = null, mixed $expected = true, ?string $name = null, ?string $condition_class = null, ?int $max_iterations = null )` | Gå tilbage til et tidligere navngivet trin, indtil en offentlig tilstandsnøgle eller `RepeatCondition`-klasse matcher. |
| `run_workflow( string $workflow_name, WorkflowBuilder $sub_builder )` | Tilføj et trin, der kører et workflow. |
| `delay( int $seconds = 0, int $minutes = 0, int $hours = 0, int $days = 0 )` | Tilføj et varigt forsinkelsestrin. Alle varigheder lægges sammen. |
| `wait_for_signal( string $name, ?string $result_key = null, ?string $step_name = null, array $match_payload = [], ?string $correlation_key = null )` | Tilføj et trin, der afventer et signal. Valgfri `match_payload` og `correlation_key` gør det muligt at ignorere uvedkommende hændelser. |
| `wait_for_signals( array $signal_names, WaitMode $mode = WaitMode::All, ?string $result_key = null, ?string $name = null, array $match_payload = [], ?string $correlation_key = null )` | Vent på alle eller nogle af flere signaler med valgfrit match af payload og korrelation. |
| `wait_for_approval( string $signal_name = 'approval', ?string $result_key = 'approval', ?string $name = null, array $match_payload = [], ?string $correlation_key = null )` | Vent på et signal om menneskelig godkendelse. |
| `wait_for_decision( string $approve_signal = 'approved', string $reject_signal = 'rejected', ?string $result_key = 'decision', ?string $name = null, array $match_payload = [], ?string $correlation_key = null )` | Vent på enten godkendelse eller afvisning, og gem en struktureret beslutningspayload. |
| `wait_for_input( string $signal_name = 'input', ?string $result_key = 'input', ?string $name = null, array $match_payload = [], ?string $correlation_key = null )` | Vent på et signal med menneskeligt input. |
| `wait_for_workflow( int\|string $workflow, ?string $result_key = null, ?string $name = null )` | Vent på, at ét workflow-id eller et workflow-id gemt i den offentlige tilstand fuldføres. |
| `wait_for_workflows( array\|string $workflows, WaitMode $mode = WaitMode::All, ?string $result_key = null, ?string $name = null, ?int $quorum = null )` | Vent på, at alle, nogle eller et quorum af flere workflows fuldføres. |
| `wait_for_workflow_group( string $group_key, WaitMode $mode = WaitMode::All, ?int $quorum = null, ?string $result_key = null, ?string $name = null )` | Vent på en tidligere startet workflowgruppe via en intern gruppenøgle. |
| `start_workflows( string $items_key, WorkflowBuilder $workflow_builder, string $result_key = 'started_workflow_ids', string $payload_key = 'item', bool $inherit_state = true, ?string $name = null, ?string $group_key = null )` | Afsend ét workflow på øverste niveau pr. runtime-element; den startede mængde kan valgfrit mærkes med en varig gruppenøgle. |
| `start_agents( string $items_key, WorkflowBuilder $workflow_builder, string $result_key = 'agent_workflow_ids', string $payload_key = 'agent_task', bool $inherit_state = true, ?string $name = null, ?string $group_key = null )` | Agentorienteret alias for `start_workflows()`. |
| `wait_for_agents( array\|string $workflows = 'agent_workflow_ids', WaitMode $mode = WaitMode::All, ?string $result_key = 'agent_results', ?string $name = null, ?int $quorum = null )` | Agentorienteret alias for `wait_for_workflows()`. |
| `wait_for_agent_group( string $group_key = 'agents', WaitMode $mode = WaitMode::All, ?int $quorum = null, ?string $result_key = 'agent_results', ?string $name = null )` | Agentorienteret alias for `wait_for_workflow_group()`. |
| `version( string $version )` | Mærk workflowdefinitionen med en version på applikationsniveau til inspektion og eksport. |
| `idempotency_key( string $key )` | Gør afsendelsen af workflowet varig for en nøgle angivet af kalderen. Afsendes det igen med samme nøgle, returneres det oprindelige workflow-id. |
| `max_transitions( int $max )` | Få workflowet til at fejle, hvis mere end `$max` trintransitions fuldføres. |
| `max_for_each_items( int $max )` | Få workflowet til at fejle, hvis et `for_each()`-trin forsøger at udvide sig til mere end `$max` elementer. |
| `max_state_bytes( int $bytes )` | Få workflowet til at fejle, hvis den offentlige tilstand vokser ud over `$bytes`. |
| `max_cost_units( int $max )` | Få workflowet til at fejle, hvis fuldførte trin bruger mere end `$max` omkostningsenheder. |
| `max_started_workflows( int $max )` | Få workflowet til at fejle, før der afsendes mere end `$max` underordnede workflows. |
| `compensate_with( string $handler_class )` | Tilknyt en kompensationshandler til det senest tilføjede trin. |
| `compensate_on_failure()` | Kør automatisk kompensation for fuldførte trin, når workflowet fejler. |
| `on_queue( string $queue )` | Angiv køen for alle trin. |
| `with_priority( Priority $priority )` | Angiv prioriteten for alle trin. |
| `max_attempts( int $max )` | Angiv maksimalt antal genforsøg pr. trin. |
| `on_cancel( string $handler_class )` | Registrer en oprydningshandlerklasse til annullering. Se [Annullering](https://queuety.inline0.dev/da/docs/workflows/cancellation). |
| `prune_state_after( int $steps = 2 )` | Aktivér automatisk beskæring af tilstanden. Fjerner trinoutput, der er ældre end tærsklen. Se [Beskæring af tilstand](https://queuety.inline0.dev/da/docs/features/state-pruning). |
| `must_complete_within( int $seconds = 0, int $minutes = 0, int $hours = 0, int $days = 0 )` | Angiv en deadline for workflowet. Alle varigheder lægges sammen. Se [Deadlines](https://queuety.inline0.dev/da/docs/workflows/deadlines). |
| `on_deadline( string $handler_class )` | Registrer en handler, der kaldes, når workflowets deadline overskrides. Se [Deadlines](https://queuety.inline0.dev/da/docs/workflows/deadlines). |
| `dispatch( array $initial_payload = [] )` | Afsend workflowet. Returnerer workflow-id'et. |

### `Queuety::workflow_status( $workflow_id )`

Hent workflowstatus. Returnerer et `WorkflowState`-objekt eller `null`.

```php
$state = Queuety::workflow_status( $workflow_id );
echo $state->name;          // 'generate_report'
echo $state->status->value; // 'running'
echo $state->current_step;  // 1
echo $state->total_steps;   // 3
print_r( $state->state );   // accumulated public state array
echo $state->wait_type;     // 'signal' or 'workflow' while blocked
echo $state->wait_mode;     // 'all', 'any', or 'quorum'
echo $state->definition_version; // 'research.v2'
echo $state->definition_hash;    // '4c7a...'
echo $state->idempotency_key;    // 'brief:42:research'
echo $state->artifact_count;     // 2
print_r( $state->budget );       // configured workflow budget + current usage
print_r( $state->wait_details ); // matched/remaining blockers, result key, correlation info
print_r( $state->artifact_keys ); // ['draft', 'citations']
```

`WorkflowState` viser også:

- `waiting_for`: signalnavnene eller workflow-id'erne, der aktuelt blokerer kørslen
- `current_step_name`: det aktuelle trins konfigurerede navn, hvis et sådant findes
- `wait_mode`: den aktuelle ventetilstand (`all`, `any` eller `quorum`), mens workflowet er blokeret
- `wait_details`: ekstra inspektionsdata, f.eks. matchede og resterende blokeringer
- `definition_version`: værdien angivet af `version()`, hvis nogen
- `definition_hash`: en deterministisk hash af workflowdefinitionen
- `idempotency_key`: den varige afsendelsesnøgle, hvis nogen
- `budget`: konfigurerede grænser samt aktuelt forbrug, hvis sikkerhedsbegrænsninger er aktiveret
- `artifact_count`: antal gemte artefakter for workflowet
- `artifact_keys`: gemte artefaktnøgler til hurtig inspektion

### `Queuety::retry_workflow( $workflow_id )`

Prøv et mislykket workflow igen fra det trin, hvor det fejlede.

```php
Queuety::retry_workflow( $workflow_id );
```

Kaster `RuntimeException`, hvis workflowet allerede er blevet kompenseret efter en fejl.

### `Queuety::pause_workflow( $workflow_id )`

Sæt et kørende workflow på pause. Arbejde, der allerede er lagt i kø for det aktuelle trin, kan stadig blive færdigt, men senere trin sættes ikke i kø, før workflowet genoptages.

```php
Queuety::pause_workflow( $workflow_id );
```

### `Queuety::resume_workflow( $workflow_id )`

Genoptag et workflow, der er sat på pause.

```php
Queuety::resume_workflow( $workflow_id );
```

### `Queuety::cancel_workflow( $workflow_id )`

Annuller et workflow, og kør eventuelle registrerede oprydningshandlere. Sætter status til `cancelled` og begraver alle afventende job og job under behandling for workflowet.

```php
Queuety::cancel_workflow( $workflow_id );
```

Kaster `RuntimeException`, hvis workflowet allerede er `completed` eller `cancelled`. Se [Annullering](https://queuety.inline0.dev/da/docs/workflows/cancellation) for detaljer.

### `Queuety::rewind_workflow( $workflow_id, $to_step )`

Rul et workflow tilbage til et tidligere trin, og kør det igen derfra. Tilstanden gendannes fra hændelsesloggen `state_after` for det angivne trin, og det næste trin sættes i kø.

```php
Queuety::rewind_workflow( $workflow_id, to_step: 1 );
```

Kaster `RuntimeException`, hvis der ikke findes en registreret tilstand for måltrinnet. Kræver [Workflowets hændelseslog](https://queuety.inline0.dev/da/docs/workflows/event-log). Se [Tidsrejse](https://queuety.inline0.dev/da/docs/workflows/time-travel) for detaljer.

### `Queuety::fork_workflow( $workflow_id )`

Forgren et kørende workflow til en uafhængig kopi i dets aktuelle tilstand. Returnerer det nye workflow-id.

```php
$forked_id = Queuety::fork_workflow( $workflow_id );
```

Det forgrenede workflow får sit eget id og kører uafhængigt af originalen. Se [Forgrening](https://queuety.inline0.dev/da/docs/workflows/forking) for detaljer.

### `Queuety::export_workflow( $workflow_id )`

Eksportér et workflows fulde eksekveringshistorik som et JSON-serialiserbart array. Omfatter workflowrækken, alle job, workflowhændelser og logposter.

```php
$data = Queuety::export_workflow( $workflow_id );
```

Se [Eksport og afspilning](https://queuety.inline0.dev/da/docs/workflows/export-replay) for strukturen JSON og anvendelsesmuligheder.

### `Queuety::replay_workflow( $data )`

Afspil et eksporteret workflow i det aktuelle miljø. Opretter et nyt workflow ud fra eksportdataene og returnerer det nye workflow-id.

```php
$new_id = Queuety::replay_workflow( $data );
```

Se [Eksport og afspilning](https://queuety.inline0.dev/da/docs/workflows/export-replay) for detaljer.

### `Queuety::replace_wp_cron()`

Erstat det indbyggede WordPress-cron-system med Queuetys scheduler. Opfanger `wp_schedule_event()`, `wp_unschedule_event()` og `wp_get_scheduled_event()` og sender tilbagevendende hændelser gennem workeren Queuety.

```php
Queuety::replace_wp_cron();
```

Fungerer kun, når WordPress er indlæst. Se [WP-Cron-erstatning](https://queuety.inline0.dev/da/docs/features/wp-cron) for detaljer.

### `Queuety::restore_wp_cron()`

Gendan WordPresss standardadfærd for cron ved at fjerne brohooks for Queuety cron.

```php
Queuety::restore_wp_cron();
```

Se [WP-Cron-erstatning](https://queuety.inline0.dev/da/docs/features/wp-cron) for begrænsninger.

### `Queuety::signal( $workflow_id, $name, $data )`

Send et signal til et workflow. Hvis workflowet aktuelt venter på dette signal, genoptages det med det samme. Ellers gemmes signalet og opfanges, når workflowet når det tilsvarende `wait_for_signal`-trin.

```php
Queuety::signal( $workflow_id, 'approved' );

// With data merged into workflow state
Queuety::signal( $workflow_id, 'approved', [
    'approved_by' => 'admin@example.com',
] );
```

Se [Workflowsignaler](https://queuety.inline0.dev/da/docs/workflows/signals) for detaljer.

### `Queuety::approve_workflow( $workflow_id, $data = [], $signal_name = 'approval' )`

Semantisk wrapper omkring `signal()` til godkendelsesforløb.

```php
Queuety::approve_workflow( $workflow_id, [
    'reviewer' => 'editor@example.com',
] );
```

### `Queuety::reject_workflow( $workflow_id, $data = [], $signal_name = 'rejected' )`

Semantisk wrapper omkring `signal()` til afvisningsforløb.

```php
Queuety::reject_workflow( $workflow_id, [
    'reason' => 'needs citations',
] );
```

### `Queuety::submit_workflow_input( $workflow_id, $data = [], $signal_name = 'input' )`

Semantisk wrapper omkring `signal()` til struktureret menneskeligt input.

```php
Queuety::submit_workflow_input( $workflow_id, [
    'notes' => 'Ship after legal review',
] );
```

### `Queuety::put_artifact( $workflow_id, $artifact_key, $content, $kind = 'json', $step_index = null, $metadata = [] )`

Gem ét varigt artefakt for et workflow.

```php
Queuety::put_artifact(
    $workflow_id,
    'research_brief',
    [ 'summary' => 'done' ],
    'json',
    metadata: [ 'source' => 'agent' ],
);
```

### `Queuety::put_current_artifact( $artifact_key, $content, $kind = 'json', $metadata = [] )`

Gem ét artefakt for det workflowtrin, der udføres aktuelt.

```php
Queuety::put_current_artifact(
    'draft',
    [ 'status' => 'ready' ],
    'json',
);
```

### `Queuety::workflow_artifact( $workflow_id, $artifact_key )`

Hent ét gemt artefakt for et workflow.

```php
$artifact = Queuety::workflow_artifact( $workflow_id, 'draft' );
```

### `Queuety::workflow_artifacts( $workflow_id, $include_content = false )`

Vis artefakter for et workflow.

```php
$artifacts = Queuety::workflow_artifacts( $workflow_id );
```

### `Queuety::delete_workflow_artifact( $workflow_id, $artifact_key )`

Slet ét artefakt for et workflow.

```php
Queuety::delete_workflow_artifact( $workflow_id, 'draft' );
```

## Tilstandsmaskiner

### `Queuety::machine( $name )`

Begynd at opbygge en tilstandsmaskine. Returnerer en `StateMachineBuilder`.

```php
use Queuety\Enums\StateMachineStatus;

$machine_id = Queuety::machine( 'agent_session' )
    ->state( 'awaiting_user' )
    ->on( 'user_message', 'planning' )
    ->state( 'planning' )
    ->action( PlanSessionAction::class )
    ->on( 'planned', 'completed' )
    ->state( 'completed', StateMachineStatus::Completed )
    ->dispatch( [ 'thread_id' => 42 ] );
```

### `StateMachineBuilder`-metoder

| Metode | Beskrivelse |
|---|---|
| `initial( string $state_name )` | Angiv starttilstanden eksplicit. |
| `state( string $state_name, ?StateMachineStatus $terminal_status = null )` | Begynd at konfigurere en tilstand. |
| `action( string\|array $action_class )` | Registrer en kølagt indgangshandling for den aktuelle tilstand. Angiv et klassenavn eller en struktureret definition med `class`, `payload` og `config`; `payload` når frem til `StateAction::handle()` som `$payload`. |
| `on( string $event, string $target, string\|array\|null $guard_class = null, ?string $name = null )` | Registrer én hændelsesovergang fra den aktuelle tilstand. Guard-funktionen accepterer samme strukturerede form som `action()`. |
| `on_queue( string $queue )` | Angiv køen, der bruges til kølagte tilstandshandlinger. |
| `with_priority( Priority $priority )` | Angiv prioriteten for kølagte tilstandshandlinger. |
| `max_attempts( int $max_attempts )` | Angiv grænsen for genforsøg på kølagte tilstandshandlinger. |
| `version( string $version )` | Mærk maskindefinitionen med en version på applikationsniveau. |
| `idempotency_key( string $key )` | Gør afsendelsen varig for en nøgle angivet af kalderen. Afsendes den igen med samme nøgle, returneres det oprindelige maskin-id. |
| `dispatch( array $initial_state = [] )` | Afsend maskinen, og returner maskin-id'et. |

Klasser for tilstandsindgangshandlinger kan også have en valgfri metode `config()` med de samme ressourceretningslinjenøgler, som workflowtrin understøtter: `concurrency_group`, `concurrency_limit` og `cost_units`.

### `Queuety::dispatch_state_machine_definition( $definition, $initial_state = [], $options = [] )`

Afsend en serialiseret definitionspakke for en tilstandsmaskine. I de fleste applikationer bør du foretrække `machine()->dispatch()`. Denne metode på lavere niveau findes, så adaptere kan starte en maskine uden direkte afhængighed af builderen.

```php
$machine_id = Queuety::dispatch_state_machine_definition(
    $definition,
    [ 'thread_id' => 42 ],
    [ 'idempotency_key' => 'thread:42' ],
);
```

### `Queuety::machine_status( $machine_id )`

Hent maskinens aktuelle status. Returnerer et `StateMachineState`-objekt eller `null`.

```php
$status = Queuety::machine_status( $machine_id );

echo $status->name;               // 'agent_session'
echo $status->status->value;      // 'waiting_event'
echo $status->current_state;      // 'awaiting_review'
print_r( $status->state );        // public machine state
print_r( $status->available_events ); // valid incoming events in the current state
```

`StateMachineState` viser også:

- `definition_version`
- `definition_hash`
- `idempotency_key`
- `error_message`
- `current_action`
- `terminal_status`

### `Queuety::machine_event( $machine_id, $event_name, $payload = [] )`

Send én ekstern hændelse til en ventende maskine.

```php
Queuety::machine_event(
    $machine_id,
    'approve',
    [
        'approved' => true,
        'reviewer' => 'editor@example.com',
    ]
);
```

Payloaden er tilgængelig for overgangenes guard-funktioner og flettes ind i maskinens offentlige tilstand, når hændelsen accepteres.

### `Queuety::list_machines( $limit = 50, $status = null )`

Vis gemte maskinrækker til inspektion.

```php
$machines = Queuety::list_machines();
$waiting  = Queuety::list_machines( status: 'waiting_event' );
```

Hver række indeholder maskin-id, navn, status, aktuel tilstand, definitionsversion, definitionens hash, idempotensnøgle og tidsstempler for livscyklussen.

### `Queuety::machine_timeline( $machine_id, $limit = 100, $offset = 0 )`

Hent den varige hændelsestidslinje for én maskine.

```php
$timeline = Queuety::machine_timeline( $machine_id );
$page_two = Queuety::machine_timeline( $machine_id, 100, 100 );
```

Hver hændelsesrække indeholder: `id`, `machine_id`, `job_id`, `state_name`, `handler`, `event`, `event_name`, `transition_name`, `queue`, `attempt`, `input`, `output`, `state_before`, `state_after`, `context`, `artifacts`, `chunks`, `error`, `duration_ms` og `created_at`.

### `Queuety::machine_trace( $machine_id )`

Hent en normaliseret sporingspakke til en tilstandsmaskinefejlsøger UI.

```php
$trace = Queuety::machine_trace( $machine_id );
```

Sporet indeholder `machine`, grupperede `states`, rå `events`, korrelerede handlinger `jobs`, `logs`, `artifacts` og `chunks`.

### `Queuety::machine_state_at( $machine_id, $event_id )`

Hent den offentlige tilstand efter en bestemt sporingshændelse for maskinen, eller `null`, hvis den ikke findes.

```php
$state = Queuety::machine_state_at( $machine_id, $event_id );
```

Se [Tilstandsmaskiner](https://queuety.inline0.dev/da/docs/state-machines) for livscyklusmodellen og brugsmønstrene.

## Workflow-skabeloner

### `Queuety::define_workflow( $name )`

Opret en workflow-builder til brug som skabelon.

```php
$builder = Queuety::define_workflow( 'onboarding' )
    ->then( CreateAccountHandler::class )
    ->then( SendWelcomeEmailHandler::class );
```

### `Queuety::register_workflow_template( $builder )`

Registrer en workflow-skabelon.

```php
Queuety::register_workflow_template( $builder );
```

### `Queuety::run_workflow( $name, $payload, $options = [] )`

Afsend en registreret workflow-skabelon efter navn. Returnerer workflow-id'et.

```php
$workflow_id = Queuety::run_workflow( 'onboarding', [ 'email' => 'user@example.com' ] );

$workflow_id = Queuety::run_workflow(
    'onboarding',
    [ 'email' => 'user@example.com' ],
    [ 'idempotency_key' => 'onboarding:user@example.com' ],
);
```

Kaster `RuntimeException`, hvis skabelonen ikke er registreret.

### `Queuety::dispatch_workflow_definition( $definition, $payload, $options = [] )`

Afsend et workflow fra en runtime-definitionspakke.

I de fleste applikationer bør du foretrække `run_workflow()` eller `workflow()->dispatch()`. Denne metode på lavere niveau gør det muligt for genbrugelige adaptere at afsende en serialiseret workflowdefinition uden afhængighed af interne metoder i workflowadministratoren.

```php
$workflow_id = Queuety::dispatch_workflow_definition(
    $definition,
    [ 'email' => 'user@example.com' ],
    [ 'idempotency_key' => 'onboarding:user@example.com' ],
);
```

### `Queuety::on_action( $hook, $workflow, $map = null, $when = null, $idempotency_key = null, $priority = 10, $accepted_args = null )`

Registrer en handling WordPress, der afsender et workflow.

```php
Queuety::on_action(
    'save_post',
    workflow: 'content_review',
    map: static fn ( int $post_id, object $post, bool $update ): array => [
        'post_id' => $post_id,
        'post_type' => $post->post_type,
        'update' => $update,
    ],
    when: static fn ( int $post_id, object $post ): bool => 'post' === $post->post_type,
    idempotency_key: static fn ( int $post_id ): string => "save_post:{$post_id}",
);
```

`$workflow` kan være enten:

- et registreret workflow-skabelonnavn
- en indlejret `WorkflowBuilder`

`map`, `when` og `idempotency_key` kører synkront i den aktuelle WordPress-anmodning. Kun workflowtrinnene kører asynkront efter afsendelsen.

Se [Handlingsudløsere](https://queuety.inline0.dev/da/docs/features/action-triggers) for den fulde vejledning.

### `Queuety::workflow_templates()`

Hent workflow-skabelonregistret.

```php
$registry = Queuety::workflow_templates();
$template = $registry->get( 'onboarding' ); // WorkflowTemplate or null
```

### `Queuety::load_workflows( $directory, $recursive )`

Indlæs og registrer alle workflowfiler fra en mappe. Hver `.php`-fil skal returnere en `WorkflowBuilder`. Returnerer antallet af registrerede workflows.

```php
$count = Queuety::load_workflows( __DIR__ . '/workflows/' );
$count = Queuety::load_workflows( __DIR__ . '/workflows/', recursive: true );
```

### `Queuety::load_workflow_file( $file_path )`

Indlæs og registrer én workflowfil. Returnerer `WorkflowTemplate` eller `null`, hvis filen ikke returnerer en builder.

```php
$template = Queuety::load_workflow_file( __DIR__ . '/workflows/onboard-user.php' );
```

## Planlægning

### `Queuety::schedule( $handler, $payload )`

Opret en tilbagevendende tidsplan. Returnerer en `PendingSchedule`-builder.

```php
Queuety::schedule( 'cleanup_handler' )
    ->every( '1 hour' )
    ->on_queue( 'maintenance' );

Queuety::schedule( 'nightly_report' )
    ->cron( '0 3 * * *' )
    ->on_queue( 'reports' );
```

### `PendingSchedule`-metoder

| Metode | Beskrivelse |
|---|---|
| `every( string $interval )` | Angiv et intervaludtryk (e.g. `1 hour`, `30 minutes`) |
| `cron( string $expression )` | Angiv et 5-felts cron-udtryk |
| `overlap( OverlapPolicy $policy )` | Angiv politik for overlap (standard: `Allow`). Se [Scheduling](https://queuety.inline0.dev/da/docs/features/scheduling). |
| `on_queue( string $queue )` | Angiv målkøen (standard: `default`) |
| `id()` | Gennemtving afsendelse, og returner tidsplanens ID |

### `Queuety::scheduler()`

Hent den interne `Scheduler`-instans.

```php
$scheduler = Queuety::scheduler();
$schedules = $scheduler->list();
$scheduler->remove( 'handler_name' );
$count = $scheduler->tick(); // manually trigger
```

## Registrering af handlers

### `Queuety::register( $name, $class )`

Registrer en handlerklasse under et navn.

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

### `Queuety::discover_handlers( $directory, $namespace )`

Find og registrer automatisk handlerklasser fra en mappe. Returnerer antallet af registrerede handlers.

```php
$count = Queuety::discover_handlers( __DIR__ . '/handlers', 'MyPlugin\\Handlers' );
```

### `Queuety::registry()`

Hent handlerregistret.

```php
$registry = Queuety::registry();
```

## Observerbarhed

### `Queuety::logger()`

Hent `Logger`-instansen til forespørgsler på logposter.

```php
$logger = Queuety::logger();
$logs   = $logger->for_job( 42 );
$logs   = $logger->for_workflow( 7 );
$logs   = $logger->for_handler( 'send_email', 50 );
$logs   = $logger->for_event( LogEvent::Failed, 50 );
$logs   = $logger->since( new \DateTimeImmutable( '-1 hour' ), 100 );
$count  = $logger->purge( 30 );
```

### `Queuety::metrics()`

Hent `Metrics`-instansen.

```php
$stats = Queuety::metrics()->handler_stats( 60 ); // last 60 minutes
```

### `Queuety::webhook_notifier()`

Hent `WebhookNotifier`-instansen.

```php
$notifier = Queuety::webhook_notifier();
$id       = $notifier->register( 'job.buried', 'https://hooks.slack.com/...' );
$webhooks = $notifier->list();
$notifier->remove( $id );
```

### `Queuety::rate_limiter()`

Hent `RateLimiter`-instansen.

```php
$limiter = Queuety::rate_limiter();
$limiter->register( 'call_openai', 60, 60 );
```

## Cache

### `Queuety::cache()`

Hent den aktive cachebackendinstans.

```php
$cache = Queuety::cache();
$cache->set( 'my_key', 'my_value', 60 );
$value = $cache->get( 'my_key' );
```

### `Queuety::set_cache( $cache )`

Tilsidesæt cachebackendenden. Kald dette før `Queuety::init()` for at bruge en brugerdefineret implementering.

```php
Queuety::set_cache( new RedisCache() );
Queuety::init( $connection );
```

### `QUEUETY_CACHE_TTL`

Standard-TTL for cache i sekunder (standard: `5`). Angiv denne konstant i `wp-config.php` for at ændre standard-TTL'en, der bruges af interne cacheoperationer.

```php
define( 'QUEUETY_CACHE_TTL', 10 );
```

Se [Caching](https://queuety.inline0.dev/da/docs/features/caching) for oplysninger om backends og automatisk registrering.

## Hændelseslog for tilstandsmaskine

### `Queuety::machine_events()`

Hent `StateMachineEventLog`-instansen.

```php
$log = Queuety::machine_events();
```

## Hændelseslog for workflow

### `Queuety::workflow_events()`

Hent `WorkflowEventLog`-instansen.

```php
$log = Queuety::workflow_events();
```

### `Queuety::workflow_timeline( $workflow_id, $limit = 100, $offset = 0 )`

Hent hele tidslinjen over hændelser for et workflow. Returnerer et array af hændelsesrækker sorteret efter ID.

```php
$events = Queuety::workflow_timeline( $workflow_id );
$next   = Queuety::workflow_timeline( $workflow_id, 100, 100 );
```

Hver hændelsesrække indeholder: `id`, `workflow_id`, `job_id`, `parent_event_id`, `step_index`, `step_name`, `step_type`, `handler`, `event`, `queue`, `attempt`, `input`, `output`, `state_before`, `state_after`, `context`, `artifacts`, `chunks`, `error`, `error_message` (kopieret fra `error.message`), `duration_ms` og `created_at`.

### `Queuety::workflow_trace( $workflow_id )`

Hent en normaliseret sporingspakke til en workflow-fejlsøger UI.

```php
$trace = Queuety::workflow_trace( $workflow_id );
```

Sporingen indeholder `workflow`, grupperet `steps`, rå `events`, `jobs`, `logs`, `artifacts`, `chunks`, `signals` og `wait_dependencies`.

### `Queuety::trace_input( $input )`

Angiv input på applikationsniveau for det workflowtrin, der kører i øjeblikket.

### `Queuety::trace_output( $output )`

Angiv output på applikationsniveau for det workflowtrin, der kører i øjeblikket.

### `Queuety::trace_context( array $context )`

Flet kontekst på applikationsniveau ind i det workflowtrin, der kører i øjeblikket.

### `Queuety::workflow_state_at( $workflow_id, $step_index )`

Hent den offentlige tilstand, efter et bestemt workflowtrin er fuldført eller genoptaget, eller `null` hvis den ikke findes.

```php
$state = Queuety::workflow_state_at( $workflow_id, 2 );
```

Se [Workflow Event Log](https://queuety.inline0.dev/da/docs/workflows/event-log) for anvendelsestilfælde og kommandoer til CLI.

## Interne instanser

Disse metoder returnerer interne instanser til avancerede anvendelsestilfælde.

| Metode | Returnerer | Beskrivelse |
|---|---|---|
| `Queuety::queue()` | `Queue` | Køhandlinger (claim, release, bury) |
| `Queuety::worker()` | `Worker` | Styring af workerprocesser |
| `Queuety::workflow_manager()` | `Workflow` | Orkestrering af workflows |
| `Queuety::machines()` | `StateMachine` | Administration af tilstandsmaskinens livscyklus |
| `Queuety::connection()` | `Connection` | Databaseforbindelse |
| `Queuety::batch_manager()` | `BatchManager` | Administration af batchlivscyklus (annullering, beskæring) |
| `Queuety::chunk_store()` | `ChunkStore` | Lagring af chunks for streamingtrin |
| `Queuety::machine_events()` | `StateMachineEventLog` | Sporingshændelser for tilstandsmaskiner og normaliserede sporingspakker |
| `Queuety::workflow_events()` | `WorkflowEventLog` | Workflow-sporingshændelser og normaliserede sporingspakker |
| `Queuety::resource_manager()` | `ResourceManager` | Adgangsprofiler for workers, vægtede budgetter og inspektion af systemhukommelse |
| `Queuety::cache()` | `Cache` | Cachebackendinstans |

## Test

### `Queuety::fake()`

Erstat køen med en in-memory-falsk kø til test. Returnerer en `QueueFake`-instans, der registrerer afsendte jobs uden at berøre databasen. `create_batch()` registrerer også falske batchmetadata; kæder verificeres via de enkelte jobs, som de sender.

```php
$fake = Queuety::fake();
SendEmailJob::dispatch( 'user@example.com', 'Hello', 'Hi!' );
$fake->assert_pushed( SendEmailJob::class );
```

### `Queuety::reset()`

Nulstil al intern tilstand, inklusive den falske kø. Kald i `tearDown()`.

```php
Queuety::reset();
```

### Metoder for `QueueFake`

| Metode | Beskrivelse |
|---|---|
| `assert_pushed( string $class, ?Closure $callback )` | Verificer, at en jobklasse blev sat i kø. Valgfrit callback filtrerer efter jobdata. |
| `assert_pushed_times( string $class, int $count )` | Verificer, at et job blev sat i kø præcis N gange. |
| `assert_not_pushed( string $class )` | Verificer, at et job aldrig blev sat i kø. |
| `assert_nothing_pushed()` | Verificer, at ingen jobs overhovedet blev sat i kø. |
| `assert_batched( ?Closure $callback )` | Verificer, at en batch blev sendt. Valgfrit callback filtrerer efter batchdata. |
| `pushed( string $class )` | Hent alle registrerede afsendelser for en klasse. Returnerer et array. |
| `batches()` | Hent alle registrerede batches. Returnerer et array. |
| `reset()` | Ryd alle registrerede jobs og batches. |

Se [Testing](https://queuety.inline0.dev/da/docs/features/testing) for komplette eksempler.

## Interfaces

### `Handler`

Interface til simple jobhandlers.

```php
interface Handler {
    public function handle( array $payload ): void;
    public function config(): array;
}
```

`config()` kan returnere `queue`, `max_attempts`, `backoff`, `rate_limit`, `concurrency_group`, `concurrency_limit` og `cost_units`.

### `Step`

Interface til workflowtrin-handlers.

```php
interface Step {
    public function handle( array $state ): array;
    public function config(): array;
}
```

`config()` kan returnere `max_attempts`, `backoff`, `concurrency_group`, `concurrency_limit` og `cost_units`.

### `Contracts\ForEachHandler`

Interface til dynamiske for-each-grenhandlers.

```php
namespace Queuety\Contracts;

interface ForEachHandler {
    public function handle_item( array $state, mixed $item, int $index ): array;
    public function config(): array;
}
```

`config()` kan returnere `max_attempts`, `backoff`, `rate_limit`, `concurrency_group`, `concurrency_limit` og `cost_units`.

### `Contracts\ForEachReducer`

Valgfri reducering af for-each-resultater.

```php
namespace Queuety\Contracts;

interface ForEachReducer {
    public function reduce( array $state, array $for_each ): array;
}
```

### `Contracts\Compensation`

Interface til handlers for kompensation af trin.

```php
namespace Queuety\Contracts;

interface Compensation {
    public function handle( array $state ): void;
}
```

### `Contracts\RepeatCondition`

Interface til løkkebetingelser, der bruges af `repeat_until()` og `repeat_while()`, når en sammenligning af tilstandsnøgler er for begrænset.

```php
namespace Queuety\Contracts;

interface RepeatCondition {
    public function matches( array $state ): bool;
}
```

### `Contracts\StateAction`

Interface til handlinger, der udføres ved kølagt tilstandsindtræden.

```php
namespace Queuety\Contracts;

interface StateAction {
    public function handle( array $state, ?string $event = null, array $event_payload = [], array $payload = [] ): array|string;
}
```

`$payload` medfører den strukturerede `payload` fra handlingsdefinitionen, hvis maskinen blev defineret med en sådan. Returner offentlige tilstandsopdateringer. Medtag `_event` og eventuelt `_event_payload`, hvis handlingen skal udløse en overgang med det samme.

Tilstandshandlinger kan også definere en valgfri metode `config()`. Queuety læser `concurrency_group`, `concurrency_limit` og `cost_units` fra den, når indgangshandlingen sættes i kø.

### `Contracts\StateGuard`

Interface til overgangsvagter for tilstandsmaskiner.

```php
namespace Queuety\Contracts;

interface StateGuard {
    public function allows( array $state, array $event_payload, string $event, array $payload = [] ): bool;
}
```

### `Contracts\Job`

Interface til selvstændige jobklasser, der kan sendes. Jobklasser indkapsler deres payload som offentlige egenskaber og eksekveringslogik i `handle()`.

```php
namespace Queuety\Contracts;

interface Job {
    public function handle(): void;
}
```

Jobklasser kan valgfrit definere en metode `middleware()`, der returnerer et array af `Contracts\Middleware`-instanser.

### `Contracts\Cache`

Interface til cachebackends. Se [Caching](https://queuety.inline0.dev/da/docs/features/caching) for indbyggede implementeringer og brugerdefinerede backends.

```php
namespace Queuety\Contracts;

interface Cache {
    public function get( string $key ): mixed;
    public function set( string $key, mixed $value, int $ttl = 0 ): void;
    public function delete( string $key ): void;
    public function has( string $key ): bool;
    public function add( string $key, mixed $value, int $ttl = 0 ): bool;
    public function flush(): void;
}
```

| Metode | Returnerer | Beskrivelse |
|---|---|---|
| `get( $key )` | `mixed` | Hent en værdi. Returnerer `null`, hvis den ikke findes eller er udløbet. |
| `set( $key, $value, $ttl )` | `void` | Gem en værdi. TTL på 0 betyder, at den ikke udløber. |
| `delete( $key )` | `void` | Fjern en værdi. |
| `has( $key )` | `bool` | Kontrollér, om en nøgle findes og ikke er udløbet. |
| `add( $key, $value, $ttl )` | `bool` | Atomisk indstilling, hvis værdien ikke findes. Returnerer `true`, hvis værdien blev sat. |
| `flush()` | `void` | Fjern alle elementer fra cachen. |

### `WorkflowEventLog`

Registrerer workflowtrins overgange med fuld sporingskontekst. Tilgås via `Queuety::workflow_events()`.

| Metode | Returnerer | Beskrivelse |
|---|---|---|
| `record_event( array $event )` | `void` | Registrer en rå sporingshændelse |
| `record_step_started( ... )` | `void` | Registrer en step_started-hændelse med input og tilstand før eksekvering |
| `record_step_completed( ... )` | `void` | Registrer en step_completed-hændelse med input, output, tilstand før og tilstand efter |
| `record_step_failed( ... )` | `void` | Registrer en step_failed-hændelse med sporingskontekst og strukturerede fejloplysninger |
| `get_timeline( int $workflow_id, ?int $limit = 100, int $offset = 0 )` | `array` | Hent workflow-sporingshændelser i rækkefølge med valgfri sideinddeling |
| `get_trace( int $workflow_id )` | `array` | Hent en normaliseret sporingspakke |
| `get_state_at_step( int $workflow_id, int $step_index )` | `array\|null` | Hent den offentlige tilstand, efter et bestemt trin er fuldført eller genoptaget |
| `prune( int $older_than_days )` | `int` | Slet hændelser, der er ældre end det angivne antal dage. Returnerer antallet af slettede rækker. |

### `StateMachineEventLog`

Registrerer hændelser for tilstandsmaskinens livscyklus, handlinger, overgange og vagter med de samme sporingsfelter som workflowhændelser.

| Metode | Returnerer | Beskrivelse |
|---|---|---|
| `record_event( array $event )` | `void` | Registrer en rå sporingshændelse for maskinen |
| `get_timeline( int $machine_id, ?int $limit = 100, int $offset = 0 )` | `array` | Hent maskinens sporingshændelser i rækkefølge med valgfri sideinddeling |
| `get_trace( int $machine_id )` | `array` | Hent en normaliseret sporingspakke for maskinen |
| `get_state_at_event( int $machine_id, int $event_id )` | `array\|null` | Hent den offentlige tilstand efter en bestemt sporingshændelse for maskinen |
| `prune( int $older_than_days )` | `int` | Slet hændelser, der er ældre end det angivne antal dage. Returnerer antallet af slettede rækker. |

### `Contracts\StreamingStep`

Interface til workflowtrin-handlers, der producerer en strøm af chunks. Hver genererede værdi gemmes straks i databasen. Se [Streaming Steps](https://queuety.inline0.dev/da/docs/workflows/streaming).

```php
namespace Queuety\Contracts;

interface StreamingStep {
    public function stream( array $state, array $existing_chunks = [] ): \Generator;
    public function on_complete( array $chunks, array $state ): array;
    public function config(): array;
}
```

| Metode | Beskrivelse |
|---|---|
| `stream( $state, $existing_chunks )` | Generator, der udsender streng-chunks. Hver udsendelse udløser en øjeblikkelig databaseskrivning. Ved genforsøg indeholder `$existing_chunks` tidligere gemte chunks. |
| `on_complete( $chunks, $state )` | Kaldes, når streamen er afsluttet. Returnerer data, der skal flettes ind i workflowtilstanden. |
| `config()` | Valgfri konfiguration. Understøtter `max_attempts`, `backoff`, `concurrency_group`, `concurrency_limit` og `cost_units`. |

### `ChunkStore`

Håndterer lagring af chunks for streamingtrin. Tilgås via `Queuety::chunk_store()`.

| Metode | Returnerer | Beskrivelse |
|---|---|---|
| `get_chunks( int $job_id )` | `string[]` | Hent alle chunks for et job, sorteret efter chunkindeks |
| `append_chunk( int $job_id, int $chunk_index, string $content, ?int $workflow_id, ?int $step_index )` | `void` | Tilføj en enkelt chunk |
| `clear_chunks( int $job_id )` | `void` | Slet alle chunks for et job |
| `chunk_count( int $job_id )` | `int` | Tæl chunks for et job |
| `get_accumulated( int $job_id )` | `string` | Sammenkæd alle chunks til én streng |

### `Heartbeat`

Statisk hjælpefunktion til at sende aktivitets-heartbeats fra trin-handlers og streamingtrin. Se [Heartbeats](https://queuety.inline0.dev/da/docs/features/heartbeats).

| Metode | Beskrivelse |
|---|---|
| `Heartbeat::init( int $job_id, Connection $conn )` | Angiv jobkonteksten. Kaldes automatisk af workeren. |
| `Heartbeat::beat( array $progress = [] )` | Send et heartbeat. Opdaterer `reserved_at` og gemmer eventuelt statusdata i `heartbeat_data`. |
| `Heartbeat::clear()` | Ryd jobkonteksten. Kaldes automatisk af workeren. |
| `Heartbeat::current_job_id()` | Hent det aktuelle job-ID (til test). |

### `Contracts\Middleware`

Interface til job-middleware. Middleware omslutter jobeksekvering i en pipeline i onion-stil.

```php
namespace Queuety\Contracts;

interface Middleware {
    public function handle( object $job, \Closure $next ): void;
}
```

## Traits

### `Dispatchable`

Tilbyder statiske afsendelsesmetoder på jobklasser, der implementerer `Contracts\Job`. Konstruktørargumenter videregives for at oprette jobinstansen.

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

class SendEmailJob implements Job {
    use Dispatchable;
    // ...
}

// Dispatches a new SendEmailJob instance
SendEmailJob::dispatch( 'user@example.com', 'Subject', 'Body' );
```

| Metode | Returnerer | Beskrivelse |
|---|---|---|
| `dispatch( ...$args )` | `PendingJob` | Opret en instans, og send den |
| `dispatch_if( bool $condition, ...$args )` | `PendingJob\|null` | Send kun, hvis `$condition` er sand |
| `dispatch_unless( bool $condition, ...$args )` | `PendingJob\|null` | Send kun, hvis `$condition` er falsk |
| `with_chain( array $jobs )` | `ChainBuilder` | Start en kæde fra denne jobklasse |

```php
// Conditional dispatch
SendEmailJob::dispatch_if( $user->wants_email, $user->email, 'Hello', 'Hi!' );
SendEmailJob::dispatch_unless( $maintenance_mode, $user->email, 'Hello', 'Hi!' );

// Chain from a job class
FetchDataJob::with_chain( [
    new ProcessDataJob(),
    new NotifyCompleteJob(),
] )->dispatch();
```

### Jobegenskaber

Jobklasser kan erklære offentlige egenskaber, som workeren læser via reflection for at tilsidesætte adfærd for genforsøg og timeout.

| Egenskab | Type | Beskrivelse |
|---|---|---|
| `$tries` | `int` | Maksimalt antal forsøg, før jobbet lægges til side |
| `$timeout` | `int` | Maksimal eksekveringstid i sekunder (kræver `pcntl`) |
| `$backoff` | `array` | Stigende forsinkelsesværdier i sekunder for hvert genforsøg |

```php
class ImportProductsJob implements Job {
    use Dispatchable;

    public int $tries = 5;
    public int $timeout = 120;
    public array $backoff = [ 10, 30, 60, 120 ];

    // ...
}
```

### `failed()`-hook

Når et job lægges til side efter at have opbrugt alle genforsøg, kalder workeren en `failed()`-metode på jobinstansen, hvis den er defineret.

```php
public function failed( \Throwable $exception ): void {
    error_log( "Job failed: {$exception->getMessage()}" );
}
```

## Indbygget middleware

Alle middlewareklasser implementerer `Contracts\Middleware` og findes i navnerummet `Queuety\Middleware`.

| Klasse | Beskrivelse |
|---|---|
| `RateLimited( int $max, int $window )` | Håndhæv en hastighedsgrænse på `$max` eksekveringer pr. `$window` sekunder |
| `Timeout( int $seconds )` | Afbryd jobbet efter `$seconds` sekunder (kræver `pcntl`) |
| `UniqueJob( ?string $key )` | Forhindr samtidig eksekvering med en databaselås |
| `WithoutOverlapping( string $key, int $release_after )` | Forhindr overlappende eksekvering med automatisk udløb af låsen |
| `ThrottlesExceptions( int $max_attempts, int $decay_minutes )` | Begræns undtagelser for at forhindre jobstorme, når en ekstern tjeneste er nede |

Se [Middleware](https://queuety.inline0.dev/da/docs/features/middleware) for oplysninger om brug og eksempler.

## Enumtyper

### `Priority`

```php
enum Priority: int {
    case Low    = 0;
    case Normal = 1;
    case High   = 2;
    case Urgent = 3;
}
```

### `JobStatus`

```php
enum JobStatus: string {
    case Pending    = 'pending';
    case Processing = 'processing';
    case Completed  = 'completed';
    case Failed     = 'failed';
    case Buried     = 'buried';
}
```

### `WorkflowStatus`

```php
enum WorkflowStatus: string {
    case Running        = 'running';
    case Completed      = 'completed';
    case Failed         = 'failed';
    case Paused         = 'paused';
    case WaitingForSignal  = 'waiting_for_signal';
    case WaitingForWorkflows = 'waiting_for_workflows';
    case Cancelled      = 'cancelled';
}
```

### `StateMachineStatus`

```php
enum StateMachineStatus: string {
    case Running = 'running';
    case WaitingEvent = 'waiting_event';
    case Completed = 'completed';
    case Failed = 'failed';
    case Paused = 'paused';
    case Cancelled = 'cancelled';
}
```

### `BackoffStrategy`

```php
enum BackoffStrategy: string {
    case Fixed       = 'fixed';
    case Linear      = 'linear';
    case Exponential = 'exponential';
}
```

### `ForEachMode`

```php
enum ForEachMode: string {
    case All = 'all';
    case FirstSuccess = 'first_success';
    case Quorum = 'quorum';
}
```

### `WaitMode`

```php
enum WaitMode: string {
    case All    = 'all';
    case Any    = 'any';
    case Quorum = 'quorum';
}
```

### `LogEvent`

```php
enum LogEvent: string {
    case Started                  = 'started';
    case Completed                = 'completed';
    case Failed                   = 'failed';
    case Buried                   = 'buried';
    case Retried                  = 'retried';
    case WorkflowStarted          = 'workflow_started';
    case WorkflowCompleted        = 'workflow_completed';
    case WorkflowFailed           = 'workflow_failed';
    case WorkflowPaused           = 'workflow_paused';
    case WorkflowResumed          = 'workflow_resumed';
    case WorkflowCancelled        = 'workflow_cancelled';
    case WorkflowRewound          = 'workflow_rewound';
    case WorkflowForked           = 'workflow_forked';
    case WorkflowDeadlineExceeded = 'workflow_deadline_exceeded';
    case Debug                    = 'debug';
}
```

### `OverlapPolicy`

```php
enum OverlapPolicy: string {
    case Allow  = 'allow';
    case Skip   = 'skip';
    case Buffer = 'buffer';
}
```

Se [Scheduling](https://queuety.inline0.dev/da/docs/features/scheduling) for oplysninger om, hvordan hver politik fungerer.

## Attributter

### `#[QueuetyHandler]`

PHP 8-attribut til automatisk registrering. Se [PHP Attributes](https://queuety.inline0.dev/da/docs/features/attributes).

```php
use Queuety\Attributes\QueuetyHandler;

#[QueuetyHandler( name: 'send_email', queue: 'emails', max_attempts: 5 )]
class SendEmailHandler implements Handler {
    // ...
}
```

## CLI-bro

### `Queuety::cli_command()`

Returnerer det publicerede rodkommandonavn for WP-CLI.

Standardrodkommandoen er `queuety`. Definér `QUEUETY_CLI_COMMAND`, før Queuety starter, hvis kommandoen skal publiceres under et andet navn.

### `Queuety::cli_command_map()`

Returnerer det serialiserbare katalog over Queuety CLI til harnesses, der skal kende den leverede kommandogrænseflade uden at gennemgå WP-CLI-klasser.

Hver post indeholder:
- et stabilt operations-ID
- den relative sti til CLI
- handlerklassen og metoden WP-CLI
- mulige eksekveringsmål
- adapteren, der normaliserer rå CLI-argumenter til en eksekveringsplan

### `Queuety::resolve_cli_command( $path, $args, $assoc_args )`

Konverterer et fortolket CLI-kald til den eksekveringsplan, som harnesset skal køre.

```php
$plan = Queuety::resolve_cli_command(
    [ 'workflow', 'export' ],
    [ '42' ],
    [ 'output' => '/tmp/workflow.json' ]
);

echo $plan['callable']; // Queuety\Queuety::export_workflow_to_file
print_r( $plan['arguments'] );
```

Eksekveringsplaner tager bevidst højde for transportlaget:
- kommandoer opløses til offentlige PHP-funktioner med normaliserede argumenter
- kataloget viser alle mulige eksekveringsmål på forhånd, mens `callable` og `transport` identificerer den gren, der er valgt for det fortolkede input

Dette er standarden, som Queuety bruger til agent-harnesses: stabilt operations-ID, offentligt API-mål og adapterstyret normalisering af CLI-specifikke forhold som standardværdier for køer, afkodning af payloads for JSON, forgrening af worker-pools og håndtering af eksportfiler for workflows.
