> ## Documentation Index
> Fetch the complete documentation index at: https://archie.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Queues

> Create a queue, send messages to it, and have workers process them one at a time in the background. Tune retries and timing in plain language, watch live health, and recover failed jobs from the error list.

A **queue** is a to-do list for your app. Your app drops a message in; a single worker later picks it up, does the work, and confirms it. If the worker fails, the message comes back and is retried. Queues are how you run slow or spiky work **in the background** without making users wait and without losing anything.

Open **Backend → App Services → Queues** to manage them.

<Note>
  Queues are per **environment**. A queue named `order-processing` in `development` is a different queue from one with the same name in `production`.
</Note>

## The queue list

The landing view lists every queue in the current environment, with live health that refreshes automatically:

<img src="https://mintcdn.com/archie-e998dbf6/C7VAvypdgbF8SE1m/features/backend/app-services/queues-and-event-bus/queues-list.png?fit=max&auto=format&n=C7VAvypdgbF8SE1m&q=85&s=b812a35571cf8d3b5b8f37ee01096bf7" alt="Queues panel list view with several queues showing the Name, Pending, In flight, Oldest, and Errors columns and the New queue button" width="1728" height="923" data-path="features/backend/app-services/queues-and-event-bus/queues-list.png" />

| Column        | Plain meaning                                                                                                 | Technical term               |
| ------------- | ------------------------------------------------------------------------------------------------------------- | ---------------------------- |
| **Name**      | The queue's identifier (with a copy button).                                                                  | —                            |
| **Pending**   | Messages waiting to be picked up.                                                                             | Queue depth                  |
| **In flight** | Messages a worker has taken but not yet confirmed.                                                            | In-flight                    |
| **Oldest**    | How long the oldest waiting message has been sitting there (e.g., "3 d ago").                                 | Age of oldest message        |
| **Errors**    | Messages that failed too many times and moved to the error list. A red badge appears when this is above zero. | Dead-letter queue (DLQ) size |

A steadily growing **Pending** count means messages arrive faster than your workers drain them — add workers or speed up processing. A growing **Errors** count means something is repeatedly failing — open the error list to investigate.

## Create a queue

Creating a queue is meant to take about ten seconds — the only required field is the name.

<Steps>
  <Step title="Click New queue">
    In the Queues panel, click **New queue**.
  </Step>

  <Step title="Name it">
    Type a name. Names are lowercase letters, numbers and hyphens, with no spaces (they become part of an internal address). If what you type contains other characters, the panel shows the cleaned-up version it will use, and warns you immediately if the name is already taken.
  </Step>

  <Step title="(Optional) Add a description">
    A short description of what the queue is for. It shows up in the queue list and detail view — useful once you have more than a couple of queues.
  </Step>

  <Step title="(Optional) Adjust the configuration">
    The **Configuration (recommended defaults)** section is pre-filled with sensible values. Change them only if you need to — see the table below.
  </Step>

  <Step title="Create the queue">
    Click **Create queue**. You land directly on the new queue's detail view, ready to receive messages.
  </Step>
</Steps>

<img src="https://mintcdn.com/archie-e998dbf6/C7VAvypdgbF8SE1m/features/backend/app-services/queues-and-event-bus/new-queue-drawer.png?fit=max&auto=format&n=C7VAvypdgbF8SE1m&q=85&s=d71cad18c4371a2fb6d5cef817b17403" alt="New queue drawer open, showing the Name field, an optional Description, and the &#x22;Configuration (recommended defaults)&#x22; section with Processing time (s), Attempts before moving to errors, and Message retention (days)" width="1728" height="923" data-path="features/backend/app-services/queues-and-event-bus/new-queue-drawer.png" />

### Settings, explained

Every setting has a safe default, shown under **Configuration (recommended defaults)**. You can change them later from the queue's **Settings** tab.

| Setting (panel label)                | Default    | Range          | What it controls (plain language)                                                                               | Technical term              |
| ------------------------------------ | ---------- | -------------- | --------------------------------------------------------------------------------------------------------------- | --------------------------- |
| **Processing time (s)**              | 30 seconds | up to 12 hours | How long a consumer has to process a message before it's retried. Set it a little longer than your slowest job. | Visibility timeout          |
| **Attempts before moving to errors** | 5          | 1–20           | How many times a message is retried before it goes to the dead-letter queue (error list).                       | Max delivery / max receives |
| **Message retention (days)**         | 4 days     | up to 14 days  | How long an unprocessed message is kept before it expires.                                                      | Message retention           |

<Warning>
  **Processing time** is the most common source of surprises. If a job legitimately takes longer than this window, another worker may start processing the same message in parallel. Set it comfortably above your slowest realistic job, or have the worker extend it while it works.
</Warning>

## The queue detail view

Click any queue to open its detail — creating a queue drops you here directly. It's organized into tabs: **Overview**, **Errors**, **Test**, and **Settings**.

### Overview

Six stat cards — three from your configuration (**Processing time**, **Retries**, **Retention**) and three live (**Pending**, **In flight**, **Failed**) — plus an **Oldest message** line and a **How to connect** panel. The connect panel shows your project's **GraphQL endpoint** with a copy button and ready-to-paste snippets for sending and receiving messages, with **GraphQL** as the default tab and **REST (curl)** as the second. This is the fastest path from "queue created" to "first message flowing".

<img src="https://mintcdn.com/archie-e998dbf6/C7VAvypdgbF8SE1m/features/backend/app-services/queues-and-event-bus/queue-detail-overview.png?fit=max&auto=format&n=C7VAvypdgbF8SE1m&q=85&s=e08529417ea71f1665042bbcf1aec61b" alt="Queue detail Overview tab — six stat cards, the Oldest message line, and the &#x22;How to connect&#x22; panel with the GraphQL endpoint and copyable send/receive snippets" width="1728" height="923" data-path="features/backend/app-services/queues-and-event-bus/queue-detail-overview.png" />

### Errors (dead-letter queue)

Messages that exhausted their attempts land here so they're never lost. The tab shows a **Failed** count and a single **Retry all** action — there is no per-message browser, so use this to confirm something needs attention and to recover once you've fixed the cause.

<img src="https://mintcdn.com/archie-e998dbf6/C7VAvypdgbF8SE1m/features/backend/app-services/queues-and-event-bus/queue-errors-tab.png?fit=max&auto=format&n=C7VAvypdgbF8SE1m&q=85&s=8e19c60bacf1a62224251860c6e33698" alt="Queue Errors tab showing a Failed count and the &#x22;Retry all&#x22; action" width="1728" height="923" data-path="features/backend/app-services/queues-and-event-bus/queue-errors-tab.png" />

* **Retry all** — moves every failed message back to the main queue to be processed again. Use this after you've fixed the cause.

### Test

Send a message by hand to confirm your worker consumes it:

<Steps>
  <Step title="Write a JSON message">
    Use the JSON editor. It validates as you type and enforces a 256 KB limit with a live size counter.
  </Step>

  <Step title="(Optional) Add a dedup key">
    A **dedup key** suppresses accidental duplicates: sending the same key twice within a short window enqueues the message only once.
  </Step>

  <Step title="Send">
    Click **Send**. You'll see confirmation that the message was enqueued and the **Pending** count tick up.
  </Step>
</Steps>

### Settings

Change the description and the mutable settings (processing time, max attempts, retention), and find the **danger zone** to delete the queue. Deleting asks you to type the queue name and warns how many messages will be discarded.

## Connect your app to a queue

Everything the panel does is available through the **GraphQL API**, so your application code sends and processes messages the same way. The connect panel gives you copy-paste snippets; the examples below show the shape.

**Send a message.**

```graphql theme={null}
mutation {
  sendMessage(
    queue: "order-processing"
    body: "{\"orderId\":\"A-1024\",\"total\":51.25}"
    # dedupKey: "order-A-1024"   # optional: suppress duplicates
  ) {
    messageId
  }
}
```

**Receive messages** (a worker pulls a batch, then confirms each once done). Receiving supports **long polling** — the call waits up to a few seconds for messages rather than returning empty immediately.

```graphql theme={null}
mutation {
  receiveMessages(queue: "order-processing", max: 10, waitSeconds: 5) {
    messageId
    body
    receiptHandle
  }
}
```

**Confirm (delete) a processed message** using the `receiptHandle` from the message you received:

```graphql theme={null}
mutation {
  deleteMessage(queue: "order-processing", receiptHandle: "…") {
    ok
  }
}
```

A typical worker loop is: `receiveMessages` → do the work → `deleteMessage`. If your worker crashes before `deleteMessage`, the message reappears after the **processing time** and is retried automatically.

<Note>
  You can also connect over **REST** — the connect panel's second tab shows the equivalent `curl` calls. GraphQL is the recommended default because it's the same endpoint as the rest of your project's API.
</Note>

## Recover from failures

<AccordionGroup>
  <Accordion title="My Errors count is going up">
    A message is failing every attempt. Open the **Errors** tab to confirm how many are stuck, and check your worker's logic and logs. Once fixed, click **Retry all** to move the error list back into the main queue.
  </Accordion>

  <Accordion title="The same message seems to be processed twice">
    This is expected under "at least once" delivery. Make your worker **idempotent** (safe to run twice for the same input) — for example, key writes on the `orderId` so a repeat is a no-op — and use a **dedup key** when sending to suppress accidental duplicate sends.
  </Accordion>

  <Accordion title="Messages get retried while the worker is still running">
    Your job takes longer than the queue's **Processing time**. Increase it on the **Settings** tab, or have the worker extend the window while it processes.
  </Accordion>

  <Accordion title="Pending keeps climbing and never drains">
    Messages arrive faster than they're processed. Run more workers in parallel (they compete for the same queue safely), make each job faster, or both.
  </Accordion>
</AccordionGroup>

## Next

<CardGroup cols={2}>
  <Card title="Event Bus" icon="tower-broadcast" href="/docs/features/backend/app-services/queues-and-event-bus/event-bus">
    Broadcast one event to many routes — including feeding one or more queues.
  </Card>

  <Card title="Using them together" icon="diagram-project" href="/docs/features/backend/app-services/queues-and-event-bus/using-them-together">
    Fan an event out to several queues and process each copy independently.
  </Card>
</CardGroup>
