
# Начало работы

## Установка

### Требования

- PHP версии 8.2 или новее и WordPress версии 6.4 или новее
- MySQL версии 8.0+ или MariaDB версии 10.6+. Обработчики получают задания и расписания с истекшим сроком с помощью `SELECT ... FOR UPDATE SKIP LOCKED`, что старые серверы отклоняют с синтаксической ошибкой.
- `mysqli` или `pdo_mysql` (см. ниже)
- WP-CLI на сервере, если вы запускаете выделенные обработчики с `wp queuety work`
- Расширения `pcntl` и `posix` PHP, если вы запускаете пулы обработчиков с `--workers` или `--min-workers`/`--max-workers`

Queuety требует либо `mysqli`, либо `pdo_mysql` в среде выполнения PHP, которая загружает WordPress и WP-CLI. Драйвер выбирается автоматически: для сред выполнения WordPress предпочтителен `mysqli`, а `pdo_mysql` остается доступен для автономного или прямого использования.

Если нужна среда выполнения с поддержкой базы данных без слоя плагина WordPress, см. раздел [Автономное использование](https://queuety.inline0.dev/ru/docs/features/standalone-use). В этом варианте используются те же соединения и таблицы среды выполнения, но отсутствуют мосты хуков WordPress и регистрация WP-CLI.

### Из zip-архива релиза

В каждом [GitHubрелизе](https://github.com/inline0/queuety/releases) есть готовый артефакт `queuety.zip`: плагин со всеми установленными зависимостями Composer. Установите последнюю версию с помощью WP-CLI:

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

Или скачайте zip-архив и загрузите его через меню «Плагины» > «Добавить новый» > «Загрузить плагин». Это самый простой способ для обычного сайта WordPress.

### Через Composer для Composer, управляемого WordPress

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

Затем активируйте плагин:

```bash
wp plugin activate queuety
```

Тип пакета — `wordpress-plugin`. Composer помещает его в каталог плагинов, только если проект требует `composer/installers` и сопоставляет этот тип с путем установки, как это делает Bedrock; кроме того, проект должен загружать собственный `vendor/autoload.php` (это также делает Bedrock). Без `composer/installers` Composer устанавливает пакет в `vendor/queuety/queuety`, где WordPress его не обнаружит, поэтому при обычной установке WordPress используйте zip-архив релиза.

### Из исходного кода при разработке

Поместите репозиторий в `wp-content/plugins/queuety`, затем установите зависимости PHP:

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

При активации Queuety создает таблицы базы данных (`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`), чтобы обработчики могли получать задания напрямую из MySQL.

По умолчанию плагин также запускает одноразовый обработчик каждую минуту через WordPress cron для очереди `default`. Это позволяет выполнять задания и рабочие процессы без оболочки на `default`, если срабатывает WordPress cron. Каждый запуск обрабатывает не более одного задания и не запускает повторяющиеся расписания, не восстанавливает застрявшие задания и не проверяет крайние сроки рабочих процессов; это выполняется только в постоянно работающем процессе `wp queuety work` ([#14](https://github.com/inline0/queuety/issues/14)). Для пользовательских очередей, повторяющихся расписаний, меньшей задержки или больших нагрузок используйте выделенные процессы `wp queuety work`.

## Настройка

Все константы необязательны. Определите их в `wp-config.php` до загрузки плагина или до запуска Queuety при встраивании в тему:

| Константа | По умолчанию | Описание |
|---|---|---|
| `QUEUETY_RETENTION_DAYS` | `7` | Срок хранения в днях для `wp queuety purge` и `Queuety::purge()`. Автоматическая очистка не выполняется |
| `QUEUETY_LOG_RETENTION_DAYS` | `0` | Читается `Config::log_retention_days()`, но пока не используется; журналы хранятся, пока вы не вызовете `Queuety::purge_logs()` ([#15](https://github.com/inline0/queuety/issues/15)) |
| `QUEUETY_MAX_EXECUTION_TIME` | `300` | Максимальное время выполнения задания в секундах до истечения срока (пока не применяется, см. раздел [Задания](https://queuety.inline0.dev/ru/docs/jobs#timeout)) |
| `QUEUETY_WORKER_SLEEP` | `1` | Пауза в секундах, когда очередь пуста |
| `QUEUETY_WORKER_MAX_JOBS` | `1000` | Максимальное число заданий до перезапуска обработчика |
| `QUEUETY_WORKER_MAX_MEMORY` | `128` | Максимальный объем памяти в МБ до перезапуска обработчика |
| `QUEUETY_RETRY_BACKOFF` | `exponential` | Стратегия увеличения задержки: `exponential`, `linear` или `fixed` |
| `QUEUETY_STALE_TIMEOUT` | `600` | Время в секундах до восстановления застрявших заданий |
| `QUEUETY_CACHE_TTL` | `5` | Срок действия кеша по умолчанию в секундах |
| `QUEUETY_DEBUG` | `false` | Включить подробное журналирование обработчика |
| `QUEUETY_CLI_COMMAND` | `queuety` | Корневое имя команды WP-CLI |
| `QUEUETY_TABLE_PREFIX` | `queuety_` | Общее базовое имя всех таблиц Queuety после префикса базы данных WordPress |
| `QUEUETY_TABLE_JOBS` | `queuety_jobs` | Имя таблицы заданий |
| `QUEUETY_TABLE_WORKFLOWS` | `queuety_workflows` | Имя таблицы рабочих процессов |
| `QUEUETY_TABLE_LOGS` | `queuety_logs` | Имя таблицы журналов |
| `QUEUETY_TABLE_SCHEDULES` | `queuety_schedules` | Имя таблицы расписаний |
| `QUEUETY_TABLE_SIGNALS` | `queuety_signals` | Имя таблицы сигналов |
| `QUEUETY_TABLE_WORKFLOW_DEPENDENCIES` | `queuety_workflow_dependencies` | Имя таблицы ожидания зависимостей рабочего процесса |
| `QUEUETY_TABLE_WORKFLOW_DISPATCH_KEYS` | `queuety_workflow_dispatch_keys` | Имя таблицы ключей идемпотентности долговечных рабочих процессов |
| `QUEUETY_TABLE_CHUNKS` | `queuety_chunks` | Имя таблицы частей потоковой передачи |
| `QUEUETY_TABLE_QUEUE_STATES` | `queuety_queue_states` | Имя таблицы состояний очередей |
| `QUEUETY_TABLE_WEBHOOKS` | `queuety_webhooks` | Имя таблицы вебхуков |
| `QUEUETY_TABLE_LOCKS` | `queuety_locks` | Имя таблицы блокировок |
| `QUEUETY_TABLE_BATCHES` | `queuety_batches` | Имя таблицы пакетов заданий |
| `QUEUETY_TABLE_WORKFLOW_EVENTS` | `queuety_workflow_events` | Имя таблицы журнала событий рабочих процессов |
| `QUEUETY_TABLE_ARTIFACTS` | `queuety_artifacts` | Имя таблицы артефактов рабочих процессов |
| `QUEUETY_TABLE_STATE_MACHINES` | `queuety_state_machines` | Имя таблицы конечных автоматов |
| `QUEUETY_TABLE_STATE_MACHINE_EVENTS` | `queuety_state_machine_events` | Имя таблицы журнала событий конечных автоматов |
| `QUEUETY_DB_DRIVER` | `auto` | Драйвер MySQL: `auto`, `mysqli` или `pdo`. `auto` предпочитает `mysqli`, если загружен WordPress, иначе `pdo_mysql`, затем `mysqli` |

Константы управления доступом к ресурсам и адаптивным пулом (`QUEUETY_RESOURCE_*`, `QUEUETY_WORKER_POOL_*`) перечислены на странице [Обработчики](https://queuety.inline0.dev/ru/docs/features/workers).

`QUEUETY_TABLE_PREFIX` меняет только часть имен таблиц Queuety. Префикс базы данных WordPress по-прежнему добавляется к результату, поэтому `$wpdb->prefix = 'wp_'` и `QUEUETY_TABLE_PREFIX = 'themequeue_'` создают таблицы вроде `wp_themequeue_jobs`. Для отдельных таблиц приоритет остается за явно заданными константами `QUEUETY_TABLE_*`.

Для автономных подключений префикс таблиц Queuety также можно задать отдельно для каждого подключения:

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

Это сохраняет префикс базы данных WordPress без изменений и меняет только сегмент имени таблицы Queuety.

## Первое задание

Создайте класс обработчика, реализующий интерфейс `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,
        ];
    }
}
```

Зарегистрируйте его и отправьте задание:

```php
use Queuety\Queuety;

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

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

Или используйте современный класс задания с методом отправки:

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

## Первый рабочий процесс

Определите обработчики шагов, реализующие интерфейс `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 [];
    }
}
```

Отправьте рабочий процесс:

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

## Запуск обработчика

```bash
wp queuety work
```

Обработчик проверяет наличие ожидающих заданий, выполняет их, продвигает рабочие процессы и при пустой очереди переходит в режим ожидания. Нажмите `Ctrl+C` для остановки; процесс завершится сразу, даже если в этот момент выполняется задание (см. раздел [Обработчики](https://queuety.inline0.dev/ru/docs/features/workers#worker-lifecycle)).

Приведенный выше `SendEmailHandler` отправляет задания в очередь `emails` через `config()`, поэтому обработчик, запущенный для `default`, их не получит. Указывайте имя каждой используемой очереди:

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

Если вы не запускаете выделенный обработчик, Queuety по-прежнему использует описанный выше резервный вариант: WordPress cron запускается раз в минуту и обрабатывает только очередь `default`, по одному заданию за запуск. Выделенный обработчик обеспечивает более высокую пропускную способность и меньшую задержку.

Для рабочей среды запустите несколько обработчиков:

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

Обрабатывайте несколько очередей в порядке приоритета:

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

## Что дальше

- [Задания](https://queuety.inline0.dev/ru/docs/jobs) — полное руководство по отправке заданий и обработчикам
- [Рабочие процессы](https://queuety.inline0.dev/ru/docs/workflows) — цепочки, параллельные шаги, условные ветвления и запуск рабочих процессов
- [Промежуточное ПО](https://queuety.inline0.dev/ru/docs/features/middleware) — ограничение частоты, управление нагрузкой и пользовательская логика конвейера
- [Пакетная обработка](https://queuety.inline0.dev/ru/docs/features/batching) — отправка групп заданий с обратными вызовами
- [Шаги потоковой передачи](https://queuety.inline0.dev/ru/docs/workflows/streaming) — сохранение данных потоком, по частям
- [Планирование](https://queuety.inline0.dev/ru/docs/features/scheduling) — повторяющиеся задания
- [Кеширование](https://queuety.inline0.dev/ru/docs/features/caching) — подключаемый слой кеширования
- [Тестирование](https://queuety.inline0.dev/ru/docs/features/testing) — QueueFake и проверки в тестах
- [CLI Справочник](https://queuety.inline0.dev/ru/docs/cli) — все доступные команды
- [PHP API](https://queuety.inline0.dev/ru/docs/api) — программный доступ
