
# Kom godt i gang

## Installation

### Krav

- PHP 8.2 eller nyere og WordPress 6.4 eller nyere
- MySQL 8.0+ eller MariaDB 10.6+. Arbejdere henter jobs og forfaldne planer med `SELECT ... FOR UPDATE SKIP LOCKED`, som ældre servere afviser med en syntaksfejl.
- `mysqli` eller `pdo_mysql` (se nedenfor)
- WP-CLI på serveren, hvis du kører dedikerede arbejdere med `wp queuety work`
- Udvidelserne `pcntl` og `posix` PHP, hvis du kører arbejderpuljer med `--workers` eller `--min-workers`/`--max-workers`

Queuety kræver enten `mysqli` eller `pdo_mysql` i det PHP-runtime, der indlæser WordPress og WP-CLI. Driveren vælges automatisk; `mysqli` foretrækkes i runtimes med WordPress, mens `pdo_mysql` fortsat er tilgængelig ved selvstændig/direkte brug af runtime.

Hvis du ønsker et databasebaseret runtime uden pluginlaget WordPress, kan du se [Selvstændig brug](https://queuety.inline0.dev/da/docs/features/standalone-use). Denne løsning bruger de samme forbindelses- og runtimetabeller, men omfatter ikke hookbroerne WordPress eller registreringen WP-CLI.

### Fra udgivelses-zipfilen

Hver [GitHub-udgivelse](https://github.com/inline0/queuety/releases) har et `queuety.zip`-aktiv: pluginnet med dets Composer-afhængigheder allerede installeret. Installér den nyeste med WP-CLI:

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

Du kan også downloade zipfilen og uploade den under Plugins > Tilføj nyt > Upload plugin. Dette er den enkleste løsning til et almindeligt WordPress-websted.

### Via Composer til Composer-administreret WordPress

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

Aktivér derefter pluginnet:

```bash
wp plugin activate queuety
```

Pakkens type er `wordpress-plugin`. Composer placerer den kun i pluginmappen, hvis projektet kræver `composer/installers` og knytter denne type til en installationssti, som Bedrock gør, og projektet skal indlæse sit eget `vendor/autoload.php` (det gør Bedrock også). Uden `composer/installers` installerer Composer den i `vendor/queuety/queuety`, hvor WordPress ikke kan finde den. Brug derfor udgivelses-zipfilen ved en almindelig WordPress-installation.

### Fra kilden under udvikling

Placér repositoryet i `wp-content/plugins/queuety`, og installér derefter PHP-afhængigheder:

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

Ved aktivering opretter Queuety sine databasetabeller (`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`), så arbejdere kan hente jobs direkte fra MySQL.

Som standard planlægger pluginnet også en engangsarbejder via WordPress cron hvert minut til køen `default`. Det giver dig en løsning uden shell til jobs og workflows, der kører på `default`, så længe WordPress cron kører. Hver kørsel behandler højst ét job og udløser ikke gentagne planer, gendanner ikke forældede jobs og kontrollerer ikke workflowfrister; disse funktioner kører kun i en langkørende `wp queuety work`-proces ([#14](https://github.com/inline0/queuety/issues/14)). Ved brugerdefinerede køer, gentagne planer, lavere latenstid eller større arbejdsbelastninger skal du skifte til dedikerede `wp queuety work`-processer.

## Konfiguration

Alle konstanter er valgfrie. Definér dem i `wp-config.php`, før pluginnet indlæses, eller før Queuety starter i en indlejret installation i temastil:

| Konstant | Standard | Beskrivelse |
|---|---|---|
| `QUEUETY_RETENTION_DAYS` | `7` | Standardalder i dage for `wp queuety purge` og `Queuety::purge()`. Intet ryddes automatisk |
| `QUEUETY_LOG_RETENTION_DAYS` | `0` | Læses af `Config::log_retention_days()`, men bruges ikke endnu; logfiler gemmes, indtil du kalder `Queuety::purge_logs()` ([#15](https://github.com/inline0/queuety/issues/15)) |
| `QUEUETY_MAX_EXECUTION_TIME` | `300` | Maks. sekunder pr. job før timeout (håndhæves ikke endnu, se [Jobs](https://queuety.inline0.dev/da/docs/jobs#timeout)) |
| `QUEUETY_WORKER_SLEEP` | `1` | Sekunder, der ventes, når køen er tom |
| `QUEUETY_WORKER_MAX_JOBS` | `1000` | Maks. antal jobs, før arbejderen genstarter |
| `QUEUETY_WORKER_MAX_MEMORY` | `128` | Maks. MB, før arbejderen genstarter |
| `QUEUETY_RETRY_BACKOFF` | `exponential` | Ventetidsstrategi: `exponential`, `linear` eller `fixed` |
| `QUEUETY_STALE_TIMEOUT` | `600` | Sekunder, før fastlåste jobs gendannes |
| `QUEUETY_CACHE_TTL` | `5` | Standard cache-TTL i sekunder |
| `QUEUETY_DEBUG` | `false` | Aktivér detaljeret logning for arbejdere |
| `QUEUETY_CLI_COMMAND` | `queuety` | Rodkommandoens WP-CLI-navn |
| `QUEUETY_TABLE_PREFIX` | `queuety_` | Fælles basisnavn for alle Queuety-tabeller efter WordPress-DB-præfikset |
| `QUEUETY_TABLE_JOBS` | `queuety_jobs` | Jobs-tabellens navn |
| `QUEUETY_TABLE_WORKFLOWS` | `queuety_workflows` | Workflows-tabellens navn |
| `QUEUETY_TABLE_LOGS` | `queuety_logs` | Logtabellens navn |
| `QUEUETY_TABLE_SCHEDULES` | `queuety_schedules` | Plantabellens navn |
| `QUEUETY_TABLE_SIGNALS` | `queuety_signals` | Signaltabellens navn |
| `QUEUETY_TABLE_WORKFLOW_DEPENDENCIES` | `queuety_workflow_dependencies` | Tabellens navn for afhængighedsventetider i workflows |
| `QUEUETY_TABLE_WORKFLOW_DISPATCH_KEYS` | `queuety_workflow_dispatch_keys` | Tabellens navn for idempotens i holdbare workflows |
| `QUEUETY_TABLE_CHUNKS` | `queuety_chunks` | Tabellens navn for streamingstykker |
| `QUEUETY_TABLE_QUEUE_STATES` | `queuety_queue_states` | Tabellens navn for køtilstande |
| `QUEUETY_TABLE_WEBHOOKS` | `queuety_webhooks` | Webhooks-tabellens navn |
| `QUEUETY_TABLE_LOCKS` | `queuety_locks` | Låsetabellens navn |
| `QUEUETY_TABLE_BATCHES` | `queuety_batches` | Batchtabellens navn |
| `QUEUETY_TABLE_WORKFLOW_EVENTS` | `queuety_workflow_events` | Tabellens navn for workflowhændelseslog |
| `QUEUETY_TABLE_ARTIFACTS` | `queuety_artifacts` | Tabellens navn for workflowartefakter |
| `QUEUETY_TABLE_STATE_MACHINES` | `queuety_state_machines` | Tabellens navn for tilstandsmaskiner |
| `QUEUETY_TABLE_STATE_MACHINE_EVENTS` | `queuety_state_machine_events` | Tabellens navn for tilstandsmaskinens hændelseslog |
| `QUEUETY_DB_DRIVER` | `auto` | MySQL-driver: `auto`, `mysqli` eller `pdo`. `auto` foretrækker `mysqli`, når WordPress er indlæst, ellers `pdo_mysql` og derefter `mysqli` |

Konstanter for ressourceallokering og adaptive puljer (`QUEUETY_RESOURCE_*`, `QUEUETY_WORKER_POOL_*`) er angivet på siden [Arbejdere](https://queuety.inline0.dev/da/docs/features/workers).

`QUEUETY_TABLE_PREFIX` ændrer kun Queuety-delen af tabelnavnene. WordPress-databasepræfikset omslutter stadig resultatet, så `$wpdb->prefix = 'wp_'` og `QUEUETY_TABLE_PREFIX = 'themequeue_'` opretter tabeller som `wp_themequeue_jobs`. Eksplicitte konstanter `QUEUETY_TABLE_*` har stadig forrang for individuelle tabeller.

Selvstændige forbindelser kan også angive tabelpræfikset Queuety pr. forbindelse:

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

Det bevarer WordPress-databasepræfikset og ændrer kun tabellens Queuety-segment.

## Dit første job

Opret en handlerklasse, der implementerer grænsefladen `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,
        ];
    }
}
```

Registrér den, og afsend jobbet:

```php
use Queuety\Queuety;

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

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

Eller brug den moderne afsendelige jobklasse:

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

## Dit første workflow

Definér trinhåndteringer, der implementerer grænsefladen `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 [];
    }
}
```

Afsend workflowet:

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

## Start en arbejder

```bash
wp queuety work
```

Arbejderen søger efter ventende jobs, udfører dem, fører workflows videre og venter, når køen er tom. Tryk på `Ctrl+C` for at stoppe; processen afsluttes straks, selv midt i et job (se [Arbejdere](https://queuety.inline0.dev/da/docs/features/workers#worker-lifecycle)).

`SendEmailHandler` ovenfor sender sine jobs til køen `emails` via `config()`, så en arbejder på `default` ikke henter dem. Angiv navnet på hver kø, du bruger:

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

Hvis du ikke kører en dedikeret arbejder, har Queuety stadig den ovenfor beskrevne WordPress cron-fallback, der kører én gang i minuttet. Den er begrænset til køen `default` og ét job pr. kørsel. Den dedikerede arbejder giver større gennemløb og lavere latenstid.

I produktion skal du køre flere arbejdere:

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

Behandl flere køer med prioritering:

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

## Hvad nu?

- [Jobs](https://queuety.inline0.dev/da/docs/jobs) for den komplette vejledning til afsendelse og handlere
- [Workflows](https://queuety.inline0.dev/da/docs/workflows) for kæder, parallelle trin, betinget forgrening og afvikling af workflows
- [Middleware](https://queuety.inline0.dev/da/docs/features/middleware) for hastighedsbegrænsning, begrænsning af gennemløb og tilpasset pipelinelogik
- [Batchbehandling](https://queuety.inline0.dev/da/docs/features/batching) for afsendelse af grupper af jobs med callbacks
- [Streamingtrin](https://queuety.inline0.dev/da/docs/workflows/streaming) for lagring af streamede data stykke for stykke
- [Planlægning](https://queuety.inline0.dev/da/docs/features/scheduling) for gentagne jobs
- [Caching](https://queuety.inline0.dev/da/docs/features/caching) for det modulære cachelag
- [Test](https://queuety.inline0.dev/da/docs/features/testing) for QueueFake og testkontroller
- [CLI-reference](https://queuety.inline0.dev/da/docs/cli) for alle tilgængelige kommandoer
- [PHP API](https://queuety.inline0.dev/da/docs/api) for programmatisk adgang
