---
title: "Laravel configuration reference: config/queen.php"
description: "Every key of config/queen.php and the queen queue connection: the 20 values read from the environment, the default the code applies, what each key does, the settings refused at start, and the upgrade from 2.0.0."
---

> Queen MQ documentation, for AI agents
> Complete self-contained summary of Queen MQ: https://queenmq.com/llms-brief.txt
> Fetch that first when the question is about the product rather than about this page.
> Index of all pages: https://queenmq.com/llms.txt

# Laravel configuration reference: config/queen.php

Every setting of the Laravel integration lives in `config/queen.php`. The file reads 20 environment variables, for what differs between environments (the broker, its credentials, the queue and group, paths, and the switches of optional features); every other setting is a plain value in the file. This page lists the 20, then every key area by area, with its default in PHP client 2.1.0 and later.

**Why:** 95 environment variables (as before 2.1.0) are 95 places a deployment can disagree with the code. Twenty for what really changes per environment, and plain values for the rest, keeps a deployment readable.

```bash
php artisan vendor:publish --tag=queen-config
```

## Set per environment

These 20 variables are the values that usually differ between environments. Each sets the key named
in its area's table below.

**Broker and queue**

| Variable | What it sets |
| --- | --- |
| `QUEEN_URL` | The broker's address, used while `QUEEN_URLS` is empty. Default `http://localhost:6632`. |
| `QUEEN_URLS` | Several broker addresses, comma-separated; they replace `QUEEN_URL`. |
| `QUEEN_BEARER_TOKEN` | The credential sent with every broker request. |
| `QUEEN_QUEUE` | The default queue, also used by the `default` pool and the `waits` entry. Default `default`. |
| `QUEEN_CONSUMER_GROUP` | The workers' consumer group, also used by the `default` pool. Default `laravel`. |
| `QUEEN_PARTITIONS` | Stripes that ordinary jobs are spread over, 1 to 1,024. Default 64. |

**Supervisor**

| Variable | What it sets |
| --- | --- |
| `QUEEN_SUPERVISOR_PREFORK` | Fork every worker from one booted Laravel. Default off. |
| `QUEEN_SUPERVISOR_COORDINATION` | Share each autoscaling pool's target with the other replicas. Default off. |
| `QUEEN_SUPERVISOR_REMOTE_STATUS` | Also publish the supervisor's status to the broker. Default off. |
| `QUEEN_SUPERVISOR_STATE_DIRECTORY` | The supervisor's private state directory. Default `storage/queen-supervisor`. |
| `QUEEN_SUPERVISOR_READ_BEARER_TOKEN` | The token for the supervisor's and the dashboard's reads. Default: the connection's token. |
| `QUEEN_SUPERVISOR_INSTALL_PATH` | The directory of the Rust binary; the launcher reads it too. Default `storage/queen-supervisor-bin`. |
| `QUEEN_SUPERVISOR_RELEASE_BASE_URL` | An HTTPS mirror of the supervisor releases. |

**Dashboard, alerts and metrics**

| Variable | What it sets |
| --- | --- |
| `QUEEN_DASHBOARD_ENABLED` | Register the dashboard routes. Default off. |
| `QUEEN_DASHBOARD_PATH` | The URL prefix of the dashboard. Default `queen`. |
| `QUEEN_DASHBOARD_DOMAIN` | The host name the dashboard answers on. |
| `QUEEN_DASHBOARD_CONSOLE_URL` | The Queen web console, for the links of the Workload page. |
| `QUEEN_NOTIFY_MAIL` | The addresses that `queen:check-waits` mails a long wait to. |
| `QUEEN_METRICS_ENABLED` | Serve the Prometheus endpoint. Default off. |
| `QUEEN_METRICS_TOKEN` | The bearer token the Prometheus scraper sends. |

A few more variables are read outside `config/queen.php`, from the environment of the process:

- `QUEEN_SDK_HTTP_TRANSPORT=guzzle` sends every request of the client through Guzzle instead of its
  cURL transport ([connection and client](#connection-and-client)).
- `QUEEN_SDK_POP_AUTOPILOT=off` turns pop autopilot off for the pops your own code sends through
  the `Queen` client. The queue driver sets autopilot on each of its pops from the `autopilot` key,
  so the variable does not change it.
- `vendor/bin/queen-supervisor` reads `QUEEN_SUPERVISOR_INSTALL_PATH` from its own environment
  ([native supervisor binary](#native-supervisor-binary)).
- The supervisors set `QUEEN_LARAVEL_*`, `QUEEN_SUPERVISOR_TELEMETRY_DIR`,
  `QUEEN_SUPERVISOR_EXITS_DIR`, `QUEEN_SUPERVISOR_LEASE_SOCKET` and `QUEEN_FORK_SERVER` for the
  workers they start. Do not set them yourself.

## How the values are read

- The package merges its own `config/queen.php` under yours, so a key you leave out keeps the
  default below. Publish the file to change a value that no variable sets.
- The published file belongs to the application. Where a value must differ per environment, add
  an `env()` call of your own ([upgrading from 2.0.0](#upgrading-from-200) shows one).
- In the tables below, a key that the file reads from a variable names it in parentheses. Every
  other key is a plain value.
- The `queen` queue connection starts from the connection and driver keys of `config/queen.php`. A
  `queen` entry in `config/queue.php` overrides any of them, and another connection with
  `'driver' => 'queen'` starts from the same values.
- A supervised worker takes its consumer group and `retry_after` from its pool, not from the
  connection, and a pool with `balance` `off` gives it `block_for` 0. Both engines do this, for
  the connection the pool works alone: another Queen connection the worker resolves, to dispatch
  onto it from a job, keeps its own configuration (PHP client 2.4.1).
- A pool that sets no `queues` or `consumer_group` takes its connection's `queue` and
  `consumer_group`; for a pool on `queen` those are the top-level ones, so `QUEEN_QUEUE` and
  `QUEEN_CONSUMER_GROUP` reach it too. The other keys a pool leaves out take the defaults of the
  [pool table](#pools).
- Write switches as `true` or `false`. The connector and the supervisor accept only a real boolean,
  and a `1` or an `'on'` is refused (`Queen Laravel after_commit must be a boolean.`). The
  dashboard, job metrics and tags are on only for `true`. The switch variables
  (`QUEEN_SUPERVISOR_PREFORK`, `QUEEN_SUPERVISOR_REMOTE_STATUS`, `QUEEN_SUPERVISOR_COORDINATION`,
  `QUEEN_DASHBOARD_ENABLED` and `QUEEN_METRICS_ENABLED`) take `true`, `1`, `yes` and `on`.

## Connection and client

| Config key | Default | Meaning |
| --- | --- | --- |
| `url` | `http://localhost:6632` | The broker's address, used while `urls` is empty. Variable: `QUEEN_URL`. |
| `urls` | unset | Several broker addresses, comma-separated in the variable; they replace `url`. A connection with a `url` of its own and no `urls` is not on this cluster. Variable: `QUEEN_URLS`. |
| `bearer_token` | unset | Sent as `Authorization: Bearer <token>` on every request. Variable: `QUEEN_BEARER_TOKEN`. |
| `headers` | `[]` | Extra HTTP headers on every request, as a PHP array. |
| `timeout` | `30000` | How long one broker request may take, in milliseconds. |
| `retry_attempts` | `3` | Tries for a request that meets a network error or a 5xx, the first included. |
| `retry_delay` | `1000` | Wait before the second try, in milliseconds; it doubles for each later try. |
| `load_balancing_strategy` | `affinity` | How requests are spread over `urls`: `affinity`, `round-robin` or `session`. |
| `enable_failover` | `true` | With several URLs, a network error or a 5xx sends the request to the next backend, one try each. |
| `affinity_hash_ring` | `150` | Virtual nodes per backend on the `affinity` hash ring. |
| `health_retry_after` | `30000` | How long a backend that failed stays out of rotation, in milliseconds. |
| `retry_429.maxAttempts` | `null` | Tries for a request rate limited with HTTP 429, the first included. When `null`: 10, unbounded for a long-poll pop. |
| `retry_429.baseMs` | `null` | First wait after a 429, in milliseconds; it doubles for each later try. When `null`: `500`. |
| `retry_429.capMs` | `null` | Longest wait after a 429, in milliseconds, at most 300,000. When `null`: `30000`. |

With a single URL the load-balancing keys have no effect. With several, `enable_failover` takes the
place of `retry_attempts`: each backend gets one try, and a backend that failed is skipped for
`health_retry_after`.

Since PHP client 2.4.4 a failover that finds every backend marked unhealthy still tries each one,
not only the first. While a cluster elects a leader, its nodes answer 503 `no_leader`: a request
waits the election out at the pace of the `Retry-After` header, for at most 10 seconds or its
`timeout`, without using up its tries. A read, or a push whose every message has a `transactionId`
(the broker drops a second copy, and a Laravel job always has one), also waits after a 503 `retry`.
A pop whose 503 says it may have run (`outcome_unknown`, `timeout` or `retry`) is never sent again,
so a lease is never taken twice. A redirect is an error, never followed or retried: check the URL.
An answer without a body where the broker always sends one (a push, an ACK, a transaction, a pop
with status 200) is an error too, no longer a success. A body that cannot be encoded as JSON, such
as a string that is not UTF-8, fails at once, with no request sent and no backend marked unhealthy.

> **Caution**
>
> Two defaults differ from the plain PHP client's, because `config/queen.php` sets its own:
> `affinity_hash_ring` is `150` under Laravel and `128` in `new Queen(...)`, and
> `health_retry_after` is `30000` ms under Laravel and `5000` ms in `new Queen(...)`.

The 429 budget is separate from `retry_attempts`. A `Retry-After` from the server wins over the
computed wait, the cap applies to both, and a 429 never moves the request to another backend. A
`null` is dropped, so the default in parentheses applies.

The client sends synchronous requests over its own cURL handles when `ext-curl` is loaded and no
proxy variable is set (`HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY` or a lower-case form); otherwise it
uses Guzzle. `QUEEN_SDK_HTTP_TRANSPORT=guzzle` forces Guzzle. It is read from the process
environment, not from the configuration, so set it where the workers start (systemd, the
container), not only in `.env`.

## Queue driver

| Config key | Default | Meaning |
| --- | --- | --- |
| `queue` | `default` | The queue a job goes to when it names none. Variable: `QUEEN_QUEUE`. |
| `consumer_group` | `laravel` | The consumer group the workers pop with. Variable: `QUEEN_CONSUMER_GROUP`. |
| `partitions` | `64` | Partition stripes that ordinary jobs are spread over, 1 to 1,024; a pop asks for at most 64. Variable: `QUEEN_PARTITIONS`. |
| `partition_prefix` | `laravel` | Start of the stripe names, `<prefix>-0000` to `<prefix>-<partitions - 1>`. |
| `retry_after` | `90` | The lease, in seconds: a job not acknowledged by then is delivered again. |
| `block_for` | `0` | How long a pop on an empty queue waits for a job, in seconds. |
| `prefetch` | `1` | Jobs a worker leases with one pop, 1 to 1,000, or `'auto'`: each pop sized from the jobs' runtime, about 250 ms of work, 1 to 16 jobs. |
| `ack_batch` | `1` | Finished jobs acknowledged in one request, 1 to `prefetch`. |
| `ack_async` | `false` | Start the next job without waiting for the answer to the last ACK. |
| `pop_ahead` | `false` | Pop the next batch while the last job of a full batch runs. |
| `autopilot` | `false` | Let the broker choose how many partitions a pop sweeps; the batch stays `prefetch`. |
| `bulk_batch` | `100` | Jobs in one push request of `Queue::bulk()`, 1 to 1,000. |
| `binary_push` | `false` | Send a dispatched job as a binary push body instead of JSON. |
| `push_compression` | `false` | With `binary_push`: frame each pushed batch the way the broker stores it and compress it with zstd in the dispatching process. |
| `framed_pop` | `false` | Ask for the popped jobs as the stored records and unpack them in the worker. |
| `after_commit` | `false` | Dispatch a job only after the open database transaction commits. |

`retry_after` must be longer than the worker's `--timeout` and than the slowest job, unless lease
renewal is on. Keep `block_for` at 0 when a worker serves a comma-separated queue list: a wait on
the first, empty queue would delay the others. A job that implements `QueenPartitionable` goes to
its own partition instead of a stripe ([queues and
stripes](/integrations/laravel/concepts/#queues-and-stripes)). `prefetch` above 1 and `pop_ahead` need
`lease_renewal`, and `ack_async` needs `ack_batch` 1
([prefetch](/integrations/laravel/concepts/#prefetch-ack_async-and-pop_ahead),
[delivery profiles](/integrations/laravel/#choose-a-delivery-profile)).

`binary_push`, `push_compression` and `framed_pop` change how the jobs travel between the driver
and the broker, and nothing else: the jobs, their order and their delivery stay the same. Turn
them on when the broker's CPU or the network limits a high job rate, because the framing, the
compression and the unpacking then run in the PHP processes.

- With `binary_push` and `push_compression`, a job released without a delay, or handed back by a
  worker that stops, travels the same way inside its transaction. A delayed job is a timer and
  stays JSON.
- `push_compression` and `framed_pop` need the zstd PHP extension (`pecl install zstd`) in the
  workers and in every process that dispatches or resolves the `Queen` client.
- `binary_push` and `push_compression` need broker 2.3.0 or later. A broker up to 2.2.0
  answers a binary body with 400, so turn the two on after every broker of the cluster is
  upgraded. `framed_pop` is safe against any broker: an older one ignores the request and answers
  JSON.
- The three are plain values with no environment variable. Add an `env()` call of your own to
  switch them per environment.

## Lease renewal

| Config key | Default | Meaning |
| --- | --- | --- |
| `lease_renewal` | `false` | Renew the lease of a running job, and stop the worker before a lease it cannot renew runs out. |
| `lease_renewal_interval` | `null` | Time between two renewals, in seconds. When `null`: `retry_after` / 3, at least 1. |
| `lease_renewal_timeout` | `5` | How long one renewal request may take for each broker URL, in seconds. |
| `lease_renewal_kill_grace` | `2` | Time between SIGTERM and SIGKILL for a worker whose lease cannot be renewed in time, in seconds. |
| `lease_renewal_safety_margin` | `1` | Time kept free before the lease deadline, in seconds. |

The timing must fit inside the lease: the interval, plus twice the timeout times the number of
broker URLs, plus 1, plus the kill grace and the safety margin, must be shorter than
`retry_after`. The defaults give 30 + 10 + 1 + 2 + 1 = 44 seconds against 90. Under the Rust
supervisor on Linux the master renews the leases, unless `supervisor.lease_service` is `false`;
anywhere else each worker starts one PHP helper
([lease renewal in the master](/integrations/laravel/supervisors/#lease-renewal-in-the-master),
[fencing](/integrations/laravel/concepts/#lease-renewal-and-fencing)).

`php artisan queen:consume` reads `retry_after` as the default of its `--lease`, and these keys
when it runs with `--auto-ack`; the timing must then fit inside `--lease`
([consume Queen messages](/integrations/laravel/consume/#lease)).

## Failed jobs

| Config key | Default | Meaning |
| --- | --- | --- |
| `sync_failed_jobs` | `true` | Keep the broker's dead-letter copy in step with Laravel's `failed_jobs` on retry, forget, flush and prune. |
| `failed_jobs_lock_store` | `null` | The cache store whose lock serializes those commands. When `null`: Laravel's default cache store. |
| `failed_jobs_lock_name` | `queen:failed-jobs` | The name of that lock. |
| `failed_jobs_lock_ttl` | `600` | How long one command may hold the lock, in seconds. |
| `failed_jobs_lock_wait` | `600` | How long a command waits for the lock, in seconds. |

When failed jobs can be retried or pruned from more than one process or host, name a store that
every worker host sees: `array` is local to one process and `file` to one host. The store's lock
must be able to check its owner, or the command fails with `The configured Queen failed-job cache
lock cannot verify ownership.` Keep the TTL above the retry budget of the broker requests, since
ownership is checked before Laravel's row changes ([failed jobs](/integrations/laravel/concepts/#failed-jobs)).

## Supervisor

| Config key | Default | Meaning |
| --- | --- | --- |
| `supervisor.poll_interval` | `3` | How often the master reads the backlog and resizes its pools, in seconds. |
| `supervisor.http_timeout` | `5` | How long one request of the master to the broker may take, in seconds. |
| `supervisor.control_ttl` | `3600` | How long a pause, continue or terminate request stays valid, in seconds, 30 to 86,400. |
| `supervisor.heartbeat_timeout` | `null` | Heartbeat age at which the master shows as stale, in seconds, at most 86,400. When `null`: one control-loop pass + 1, at least 15. |
| `supervisor.read_bearer_token` | unset | Token for the depth reads, the event-driven poll, the dashboard's reads and `queen:check-waits`. When unset: the connection's token. Variable: `QUEEN_SUPERVISOR_READ_BEARER_TOKEN`. |
| `supervisor.shutdown_grace` | `75` | How long a stopping worker may finish its job before it is killed, in seconds. |
| `supervisor.process_limit` | `256` | Most child processes the master runs, renewal helpers included, at most 4,096. |
| `supervisor.state_directory` | `storage/queen-supervisor` | The private directory for status, the lock, controls, telemetry, exit markers and the notes of workers whose pops fail. Variable: `QUEEN_SUPERVISOR_STATE_DIRECTORY`. |
| `supervisor.telemetry_ttl` | `300` | How long worker runtime samples are kept for the `time` strategy, in seconds. |
| `supervisor.remote_status.enabled` | `false` | Also publish the status to the broker, for a dashboard on another host. Variable: `QUEEN_SUPERVISOR_REMOTE_STATUS`. |
| `supervisor.remote_status.connection` | `queen` | The queue connection whose broker and write credential are used. |
| `supervisor.remote_status.namespace` | `queen-supervisor` | The key/value namespace. |
| `supervisor.remote_status.key` | a slug of `APP_NAME` and `APP_ENV`, such as `laravel-production` | The publication group, one per application and environment on a broker; see the [group naming contract](/reference/supervisor-status/#identity-and-keys). |
| `supervisor.remote_status.interval` | `null` | Time between two publishes, in seconds, shorter than `heartbeat_timeout`. When `null`: `poll_interval`. |
| `supervisor.remote_status.ttl` | `null` | How long a published copy lives, in seconds, at most 86,400. When `null`: twice `heartbeat_timeout`, at least 300. |
| `supervisor.prefork` | `false` | Boot Laravel once in a fork server and fork every worker from it; a pool's `prefork` wins. Variable: `QUEEN_SUPERVISOR_PREFORK`. |
| `supervisor.event_driven` | `false` | Resize a pool when jobs arrive, through a read-only long poll, instead of at the next poll. |
| `supervisor.lease_service` | `true` | Rust engine on Linux: the master renews the leases of every `lease_renewal` worker; `false` starts one PHP helper beside each. |
| `supervisor.coordination.enabled` | `false` | Share each autoscaling pool's target with the other replicas of this supervisor. Variable: `QUEEN_SUPERVISOR_COORDINATION`. |
| `supervisor.coordination.connection` | `queen` | The queue connection whose broker and write credential hold the replica keys. |
| `supervisor.coordination.namespace` | `queen-supervisor` | The key/value namespace. |

Both engines read this section and publish remote status. `lease_service` acts only under the Rust
engine on Linux: the PHP engine always starts a helper for each worker that renews leases. Without
a `shutdown_grace` key the default is the longest pool `timeout` plus 15 seconds, which is the same
75 with the shipped pool. The state directory must be private to the supervisor's user
([prepare it](/integrations/laravel/supervisors/#prepare-a-private-state-directory)). The guides cover
[remote status](/integrations/laravel/dashboard/#a-supervisor-on-another-host),
[prefork](/integrations/laravel/supervisors/#prefork-workers),
[event-driven scaling](/integrations/laravel/supervisors/#event-driven-scaling) and
[replicas](/integrations/laravel/supervisors/#several-replicas).

## Pools

Each entry of `supervisor.supervisors` is a pool. The file ships one, `default`, with these keys
([configure a pool](/integrations/laravel/supervisors/#configure-a-pool)).

| Config key | Default | Meaning |
| --- | --- | --- |
| `connection` | `queen` | The Laravel queue connection the workers use; it must use the `queen` driver. |
| `consumer_group` | the connection's `consumer_group`; for `queen`, the top-level one (`QUEEN_CONSUMER_GROUP`) | The consumer group of the pool's workers. |
| `queues` | the connection's `queue`; for `queen`, the top-level one (`QUEEN_QUEUE`) | The queues the pool serves, as an array or a comma-separated string. |
| `balance` | `auto` | `auto` follows the backlog, `simple` runs a fixed count, `off` gives every worker the whole queue list. |
| `strategy` | `size` | How `auto` sizes the pool: `size` from the backlog, `time` from the backlog times the job runtime. |
| `min_processes` | `1` | Fewest workers of the pool. |
| `min_processes_per_queue` | `0` | Workers that every queue of an `auto` pool keeps without a backlog. |
| `fast_scale_up` | `false` | Close half of the gap to the target in each cycle while the pool grows. |
| `prefork` | `null` | This pool's own prefork: `false` spawns its workers, `true` forks them, `null` follows `supervisor.prefork`. |
| `max_processes` | `10` | Most workers of the pool, and the size of a `simple` pool that sets no `processes`. |
| `target_jobs_per_process` | `10` | Backlog jobs per worker that the `size` strategy aims at. |
| `target_clear_seconds` | `60` | Time in which the `time` strategy aims to clear the backlog, in seconds. |
| `default_runtime_seconds` | `1` | Job runtime the `time` strategy uses before the workers report one, in seconds. |
| `balance_cooldown` | `3` | Least time between two resizes of the pool, in seconds. |
| `balance_max_shift` | `1` | Most workers added or removed in one resize. |
| `scale_down_delay` | `10` | How long a lower target must hold before workers drain, in seconds. |
| `restart_backoff` | `1` | First wait before a crashed worker restarts, in seconds; it doubles with each crash in a row. |
| `restart_backoff_max` | `30` | Longest restart wait, and the wait of an open circuit before a probe worker, in seconds. |
| `stable_after` | `60` | Runtime after which a worker's exit restarts at once and a probe closes the circuit, in seconds. |
| `sleep` | `1` | `--sleep`: how long a worker sleeps when no job is available, in seconds. |
| `timeout` | `60` | `--timeout`: how long one job may run before Laravel kills the worker, in seconds. |
| `retry_after` | `90` | The lease of this pool's workers, in seconds. |
| `tries` | `3` | `--tries`: attempts before a job fails; 0 means no limit. |
| `memory` | `128` | `--memory`: the worker exits after a job above this many megabytes. |
| `backoff` | `0` | `--backoff`: wait before a failed job is tried again, in seconds. |
| `max_jobs` | `0` | `--max-jobs`: jobs after which a worker exits; 0 means no limit. |
| `max_time` | `0` | `--max-time`: time after which a worker exits, in seconds; 0 means no limit. |
| `rest` | `0` | `--rest`: pause between two jobs, in seconds. |
| `force` | `false` | `--force`: run jobs in maintenance mode too. |
| `quiet` | `true` | `--quiet`: no console output for each job. |

A pool's `retry_after` must be longer than its `timeout`, and `shutdown_grace` longer than every
pool's `timeout`. Without a `retry_after` key, a pool takes its connection's. The pool keys and the
way they scale are explained in [how a pool scales](/integrations/laravel/supervisors/#how-a-pool-scales)
and [run the PHP engine](/integrations/laravel/supervisors/#run-the-php-engine).

## Dashboard

| Config key | Default | Meaning |
| --- | --- | --- |
| `dashboard.enabled` | `false` | Register the dashboard routes. Variable: `QUEEN_DASHBOARD_ENABLED`. |
| `dashboard.path` | `queen` | The URL prefix of the dashboard. Variable: `QUEEN_DASHBOARD_PATH`. |
| `dashboard.domain` | unset | The host name the routes answer on; unset answers on every host. Variable: `QUEEN_DASHBOARD_DOMAIN`. |
| `dashboard.middleware` | `['web']` | Middleware in front of the dashboard; `web` is always kept, so add your authentication. |
| `dashboard.refresh_seconds` | `5` | How often a page refreshes itself, in seconds; a value outside 2 to 60 gives 5. |
| `dashboard.allow_local` | `true` | Let everyone in, in the `local` and `testing` environments, while no `viewQueenDashboard` Gate exists. |
| `dashboard.failed_jobs_limit` | `50` | Rows on one page of failed jobs; a value outside 1 to 200 gives 50. |
| `dashboard.console_url` | unset | The address of the Queen web console, which the Workload page then links each queue to. Variable: `QUEEN_DASHBOARD_CONSOLE_URL`. |

In production the dashboard lets nobody in until the application defines the `viewQueenDashboard`
Gate ([authorize production access](/integrations/laravel/dashboard/#authorize-production-access)). A path,
domain or middleware entry that is not safe stops the application at boot while the dashboard is
on. An invalid `console_url`, which must be an `http` or `https` URL without user info, query or
fragment, does not: it is reported to the log at boot and the Workload page shows no links
([in the queue now](/integrations/laravel/dashboard/#in-the-queue-now)).

## Monitoring

| Config key | Default | Meaning |
| --- | --- | --- |
| `waits` | `['queen:default' => 60]` | Seconds the oldest job of a `connection:queue` may wait before `queen:check-waits` reports it. |
| `notifications.mail` | unset | Comma-separated addresses that `queen:check-waits` mails a long wait to. Variable: `QUEEN_NOTIFY_MAIL`. |
| `notifications.throttle_minutes` | `5` | Least time between two notifications for one queue and group, in minutes; 0 turns the limit off. |
| `job_metrics.enabled` | `true` | Count jobs, failures and runtime per job class in every worker, for the Jobs page. |
| `job_metrics.connection` | `queen` | The queue connection whose broker stores the counts. |
| `job_metrics.namespace` | `queen-metrics` | The key/value namespace. |
| `tags.enabled` | `true` | Tag jobs when they are pushed, and record the jobs that carry a monitored tag. |
| `tags.connection` | `queen` | The queue connection whose broker stores the recorded jobs. |
| `tags.namespace` | `queen-metrics` | The key/value namespace. |
| `tags.retention_minutes` | `1440` | How long a recorded job stays listed, in minutes. |
| `metrics.enabled` | `false` | Serve the Prometheus endpoint. Variable: `QUEEN_METRICS_ENABLED`. |
| `metrics.path` | `queen/metrics` | The path of the endpoint. |
| `metrics.token` | unset | The bearer token the scraper sends, 32 characters or more; required when on. Variable: `QUEEN_METRICS_TOKEN`. |

The file sets one `waits` entry, for the queue in `QUEEN_QUEUE`; add the other queues to the array.
Workers record monitored tags only while `job_metrics.enabled` is on too. The guide covers
[jobs per class](/integrations/laravel/monitoring/#jobs-per-class),
[monitored tags](/integrations/laravel/monitoring/#monitored-tags),
[long-wait alerts](/integrations/laravel/monitoring/#long-wait-alerts) and the
[Prometheus endpoint](/integrations/laravel/monitoring/#prometheus-and-kubernetes-autoscaling).

## Native supervisor binary

| Config key | Default | Meaning |
| --- | --- | --- |
| `supervisor_binary.install_path` | `storage/queen-supervisor-bin` | The directory `queen:supervisor-install` puts the Rust binary in. Variable: `QUEEN_SUPERVISOR_INSTALL_PATH`. |
| `supervisor_binary.release_base_url` | unset | An HTTPS mirror to download the manifest and the archive from. When unset: the GitHub release of the pinned version. Variable: `QUEEN_SUPERVISOR_RELEASE_BASE_URL`. |
| `supervisor_binary.manifest` | `null` | The release manifest to install from, a URL or a local file. When `null`: `queen-supervisor-manifest.json` of the release. |
| `supervisor_binary.manifest_sha256` | `null` | The SHA-256 the manifest must have, from one you verified against its Sigstore bundle. |

The launcher, `vendor/bin/queen-supervisor`, reads neither `config/queen.php` nor `.env`. It looks
for the binary in `QUEEN_SUPERVISOR_INSTALL_PATH` from its own environment, and otherwise in
`storage/queen-supervisor-bin` under the directory it starts in. When you install elsewhere, set
the variable in the service's environment too
([run the Rust engine](/integrations/laravel/supervisors/#run-the-rust-engine)). The user that runs the
launcher must own the installation. Install as that user, or as root with
`queen:supervisor-install --owner=<user>` (PHP client 2.4.2), or copy it into a container image
with `COPY --chown` ([build the image](/integrations/laravel/kubernetes/#build-the-image)).

## Refused at start

These rules are checked before a job runs. The connector checks when Laravel opens the connection,
so `queue:work` fails at start and a dispatch throws `InvalidArgumentException`. The supervisor
checks when either engine starts, and `php artisan queen:supervisor-config` shows the same error.

| Rule | Checked by | Error |
| --- | --- | --- |
| `partitions` is 1 to 1,024 | connector | `Queen Laravel partitions must be an integer in the range 1..1024.` |
| `prefetch` is 1 to 1,000 or `'auto'` | connector, supervisor | `Queen Laravel prefetch must be an integer in the range 1..1000.` |
| `ack_batch` is 1 to `prefetch` | connector | `Queen Laravel ack_batch must be an integer in the range 1..4.` (with `prefetch` 4) |
| `prefetch` above 1, or `'auto'`, needs `lease_renewal` | connector | `Queen Laravel prefetch [4] requires lease_renewal so every prefetched lease remains fenced while Laravel executes synchronous job code.` |
| A pool's connection with `prefetch` above 1 has `lease_renewal` | supervisor | `Queen supervisor [default] connection prefetch [4] requires lease_renewal.` |
| `pop_ahead` needs `lease_renewal` | connector | `Queen Laravel pop_ahead requires lease_renewal so the batch it pops ahead remains fenced.` |
| `ack_async` needs `ack_batch` 1 | connector | `Queen Laravel ack_async requires ack_batch 1: a batch already defers its ACKs.` |
| `binary_push`, `push_compression` and `framed_pop` are `true` or `false` | connector | `Queen Laravel binary_push must be a boolean.` |
| `framed_pop`, or `binary_push` with `push_compression`, has the zstd extension | connector, as a `RuntimeException` | `framedPop needs the zstd extension (pecl install zstd)` |
| The renewal timing fits in `retry_after` | connector | `Queen Laravel lease_renewal timing is unsafe: interval + two request budgets + retry + kill grace + safety margin must be shorter than retry_after.` |
| The same rule for a pool, where a renewal may try every broker URL | supervisor | `Queen supervisor [default] lease renewal timing budget [44 s] must be shorter than retry_after [30 s]. It is the renewal interval [10 s], twice a renewal that tries every broker URL [5 s x 3 URLs], the kill grace [2 s], the safety margin [1 s] and 1 s. Raise retry_after, or lower lease_renewal_timeout or lease_renewal_interval.` (three URLs; the budget and its parts since PHP client 2.4.4) |
| A pool's `retry_after` exceeds its `timeout` | supervisor | `Queen supervisor [default] retry_after must be longer than timeout.` |
| `shutdown_grace` exceeds every pool's `timeout` | supervisor | `Queen supervisor shutdown_grace must be longer than every worker timeout.` |
| The pools fit `process_limit`, two slots per worker with lease renewal | supervisor | `Queen supervisor [default] exceeds process_limit [256].` |
| An `auto` pool's `max_processes` covers its queues | supervisor | `Queen supervisor [default] max_processes must cover every queue when balance is auto.` |
| `remote_status.key` is a string when remote status is on, as the default is | supervisor | `Queen supervisor remote_status.key must be a string when remote status is enabled.` |
| `metrics.token` has 32 characters or more when the endpoint is on | application boot | `queen.metrics.token must be a secret of at least 32 characters.` |

The supervisor also refuses `max_processes` below `min_processes`, `min_processes_per_queue` on a
pool that is not `auto` or too large for `max_processes`, a `balance_max_shift` above
`max_processes`, a switch such as `event_driven` or `lease_service` that is not `true` or `false`,
and a `control_ttl` or `heartbeat_timeout` that a control-loop pass does not fit in.
`php artisan queen:supervisor-config --pretty` prints what either engine will run, with the tokens
redacted.

## Upgrading from 2.0.0

In PHP client 2.0.0, `config/queen.php` read 95 environment variables; in 2.1.0 it reads the 20
[above](#set-per-environment). The other values are now plain settings in the file, with the
defaults they had. What changes for you depends on the file your application uses:

- **You published `config/queen.php` under 2.0.0 and keep it.** The file is yours, so it still
  reads every variable it reads today. Only `QUEEN_SUPERVISOR_LEASE_SERVICE` stops working, because
  the Rust master read it, not the file. Put `'lease_service' => false` in the `supervisor` section
  instead.
- **You did not publish it, or you publish it again.** The new file ignores the variables of the
  tables below. Write each value your environments set at its key.

The published file belongs to the application, and you can add `env()` wherever a value must differ
per environment. For example, `'max_processes' => (int) env('QUEUE_MAX_WORKERS', 10)` in a pool
reads `QUEUE_MAX_WORKERS`, a variable of your own: Queen does not know that name, and any name
works. `env()` turns `true` and `false` into booleans and returns every other value as a string, so
cast a number with `(int)` and write a switch as `true` or `false`. The connection and driver keys
can also go on the `queen` connection in `config/queue.php`, where they win over `config/queen.php`.

Two settings change in other ways:

- `QUEEN_SUPERVISOR_LEASE_SERVICE` is gone, whichever file you use. The supervisor released with
  PHP client 2.1.0 reads the key `supervisor.lease_service` (default `true`) from the document
  `queen:supervisor-config` hands it, and no longer reads the variable. When the key is `false` the
  master logs
  `lease renewal: off in the master, queen.supervisor.lease_service is false: one helper process per worker`.
- `supervisor.remote_status.key` is no longer required in the new file. It defaults to a slug of
  `APP_NAME` and `APP_ENV`, such as `laravel-production`, so supervisor hosts and web hosts that
  share both values agree on it. Two applications that keep Laravel's default `APP_NAME` on one
  broker need a key of their own. If you change the key, change it on every supervisor host and web
  host in one deploy.

`queen.x` below is the key `x` of `config/queen.php`, and the default is the value the new file
sets:

| Variable in 2.0.0 | Config key in 2.1.0 | Default |
| --- | --- | --- |
| `QUEEN_TIMEOUT` | `queen.timeout` | `30000` ms |
| `QUEEN_RETRY_ATTEMPTS` | `queen.retry_attempts` | `3` |
| `QUEEN_RETRY_DELAY` | `queen.retry_delay` | `1000` ms |
| `QUEEN_LB_STRATEGY` | `queen.load_balancing_strategy` | `affinity` |
| `QUEEN_ENABLE_FAILOVER` | `queen.enable_failover` | `true` |
| `QUEEN_AFFINITY_HASH_RING` | `queen.affinity_hash_ring` | `150` |
| `QUEEN_HEALTH_RETRY_AFTER` | `queen.health_retry_after` | `30000` ms |
| `QUEEN_RETRY_429_MAX_ATTEMPTS` | `queen.retry_429.maxAttempts` | `null` |
| `QUEEN_RETRY_429_BASE_MS` | `queen.retry_429.baseMs` | `null` |
| `QUEEN_RETRY_429_CAP_MS` | `queen.retry_429.capMs` | `null` |
| `QUEEN_PARTITION_PREFIX` | `queen.partition_prefix` | `laravel` |
| `QUEEN_RETRY_AFTER` | `queen.retry_after`, and `retry_after` of the `default` pool | `90` |
| `QUEEN_BLOCK_FOR` | `queen.block_for` | `0` |
| `QUEEN_PREFETCH` | `queen.prefetch` | `1` |
| `QUEEN_ACK_BATCH` | `queen.ack_batch` | `1` |
| `QUEEN_ACK_ASYNC` | `queen.ack_async` | `false` |
| `QUEEN_POP_AHEAD` | `queen.pop_ahead` | `false` |
| `QUEEN_AUTOPILOT` | `queen.autopilot` | `false` |
| `QUEEN_LEASE_RENEWAL` | `queen.lease_renewal` | `false` |
| `QUEEN_LEASE_RENEWAL_INTERVAL` | `queen.lease_renewal_interval` | `null` (`retry_after` / 3) |
| `QUEEN_LEASE_RENEWAL_TIMEOUT` | `queen.lease_renewal_timeout` | `5` |
| `QUEEN_LEASE_RENEWAL_KILL_GRACE` | `queen.lease_renewal_kill_grace` | `2` |
| `QUEEN_LEASE_RENEWAL_SAFETY_MARGIN` | `queen.lease_renewal_safety_margin` | `1` |
| `QUEEN_BULK_BATCH` | `queen.bulk_batch` | `100` |
| `QUEEN_AFTER_COMMIT` | `queen.after_commit` | `false` |
| `QUEEN_SYNC_FAILED_JOBS` | `queen.sync_failed_jobs` | `true` |
| `QUEEN_FAILED_JOBS_LOCK_STORE` | `queen.failed_jobs_lock_store` | `null` |
| `QUEEN_FAILED_JOBS_LOCK_NAME` | `queen.failed_jobs_lock_name` | `queen:failed-jobs` |
| `QUEEN_FAILED_JOBS_LOCK_TTL` | `queen.failed_jobs_lock_ttl` | `600` |
| `QUEEN_FAILED_JOBS_LOCK_WAIT` | `queen.failed_jobs_lock_wait` | `600` |
| `QUEEN_SUPERVISOR_POLL_INTERVAL` | `queen.supervisor.poll_interval` | `3` |
| `QUEEN_SUPERVISOR_HTTP_TIMEOUT` | `queen.supervisor.http_timeout` | `5` |
| `QUEEN_SUPERVISOR_CONTROL_TTL` | `queen.supervisor.control_ttl` | `3600` |
| `QUEEN_SUPERVISOR_HEARTBEAT_TIMEOUT` | `queen.supervisor.heartbeat_timeout` | `null` (computed) |
| `QUEEN_SUPERVISOR_SHUTDOWN_GRACE` | `queen.supervisor.shutdown_grace` | `75` |
| `QUEEN_SUPERVISOR_PROCESS_LIMIT` | `queen.supervisor.process_limit` | `256` |
| `QUEEN_SUPERVISOR_TELEMETRY_TTL` | `queen.supervisor.telemetry_ttl` | `300` |
| `QUEEN_SUPERVISOR_EVENT_DRIVEN` | `queen.supervisor.event_driven` | `false` |
| `QUEEN_SUPERVISOR_LEASE_SERVICE` | `queen.supervisor.lease_service`, a new key | `true` |
| `QUEEN_SUPERVISOR_REMOTE_STATUS_CONNECTION` | `queen.supervisor.remote_status.connection` | `queen` |
| `QUEEN_SUPERVISOR_REMOTE_STATUS_NAMESPACE` | `queen.supervisor.remote_status.namespace` | `queen-supervisor` |
| `QUEEN_SUPERVISOR_REMOTE_STATUS_KEY` | `queen.supervisor.remote_status.key` | a slug of `APP_NAME` and `APP_ENV`; required before |
| `QUEEN_SUPERVISOR_REMOTE_STATUS_INTERVAL` | `queen.supervisor.remote_status.interval` | `null` (`poll_interval`) |
| `QUEEN_SUPERVISOR_REMOTE_STATUS_TTL` | `queen.supervisor.remote_status.ttl` | `null` (computed) |
| `QUEEN_SUPERVISOR_COORDINATION_CONNECTION` | `queen.supervisor.coordination.connection` | `queen` |
| `QUEEN_SUPERVISOR_COORDINATION_NAMESPACE` | `queen.supervisor.coordination.namespace` | `queen-supervisor` |
| `QUEEN_DASHBOARD_REFRESH_SECONDS` | `queen.dashboard.refresh_seconds` | `5` |
| `QUEEN_DASHBOARD_ALLOW_LOCAL` | `queen.dashboard.allow_local` | `true` |
| `QUEEN_DASHBOARD_FAILED_JOBS_LIMIT` | `queen.dashboard.failed_jobs_limit` | `50` |
| `QUEEN_WAIT_THRESHOLD` | `queen.waits['queen:<queue>']` | `60` |
| `QUEEN_NOTIFY_THROTTLE_MINUTES` | `queen.notifications.throttle_minutes` | `5` |
| `QUEEN_JOB_METRICS` | `queen.job_metrics.enabled` | `true` |
| `QUEEN_JOB_METRICS_CONNECTION` | `queen.job_metrics.connection` | `queen` |
| `QUEEN_JOB_METRICS_NAMESPACE` | `queen.job_metrics.namespace` | `queen-metrics` |
| `QUEEN_TAGS` | `queen.tags.enabled` | `true` |
| `QUEEN_TAGS_CONNECTION` | `queen.tags.connection` | `queen` |
| `QUEEN_TAGS_NAMESPACE` | `queen.tags.namespace` | `queen-metrics` |
| `QUEEN_TAGS_RETENTION_MINUTES` | `queen.tags.retention_minutes` | `1440` |
| `QUEEN_METRICS_PATH` | `queen.metrics.path` | `queen/metrics` |
| `QUEEN_SUPERVISOR_MANIFEST` | `queen.supervisor_binary.manifest` | `null` |
| `QUEEN_SUPERVISOR_MANIFEST_SHA256` | `queen.supervisor_binary.manifest_sha256` | `null` |

These set the `default` pool, `queen.supervisor.supervisors.default`. A pool you added never read
them:

| Variable in 2.0.0 | Key of the `default` pool | Default |
| --- | --- | --- |
| `QUEEN_SUPERVISOR_BALANCE` | `balance` | `auto` |
| `QUEEN_SUPERVISOR_STRATEGY` | `strategy` | `size` |
| `QUEEN_SUPERVISOR_MIN_PROCESSES` | `min_processes` | `1` |
| `QUEEN_SUPERVISOR_MIN_PROCESSES_PER_QUEUE` | `min_processes_per_queue` | `0` |
| `QUEEN_SUPERVISOR_FAST_SCALE_UP` | `fast_scale_up` | `false` |
| `QUEEN_SUPERVISOR_MAX_PROCESSES` | `max_processes` | `10` |
| `QUEEN_SUPERVISOR_TARGET_JOBS` | `target_jobs_per_process` | `10` |
| `QUEEN_SUPERVISOR_TARGET_CLEAR_SECONDS` | `target_clear_seconds` | `60` |
| `QUEEN_SUPERVISOR_DEFAULT_RUNTIME_SECONDS` | `default_runtime_seconds` | `1` |
| `QUEEN_SUPERVISOR_BALANCE_COOLDOWN` | `balance_cooldown` | `3` |
| `QUEEN_SUPERVISOR_BALANCE_MAX_SHIFT` | `balance_max_shift` | `1` |
| `QUEEN_SUPERVISOR_SCALE_DOWN_DELAY` | `scale_down_delay` | `10` |
| `QUEEN_SUPERVISOR_RESTART_BACKOFF` | `restart_backoff` | `1` |
| `QUEEN_SUPERVISOR_RESTART_BACKOFF_MAX` | `restart_backoff_max` | `30` |
| `QUEEN_SUPERVISOR_STABLE_AFTER` | `stable_after` | `60` |

Source: https://queenmq.com/integrations/laravel/configuration/index.mdx
