# `Celery.Backend.Redis`
[🔗](https://github.com/hacktobeer/celery-elixir/blob/v0.1.0/lib/celery/backend/redis.ex#L1)

Redis result store backend for Celery (ported from `celery.backends.redis.RedisBackend`
and `celery.backends.base.KeyValueStoreBackend`).

Stores and retrieves task state, results, tracebacks, group metadata, and chord counters
in Redis using the exact key layout and JSON wire structure of Python Celery:
- Task metadata key: `celery-task-meta-<task_id>`
- Group metadata key: `celery-taskset-meta-<group_id>`
- Chord unlock key: `chord-unlock-<group_id>`
- Pub/Sub channel: `celery-task-meta-<task_id>` (published on every `store_result`)

# `delete_group`

```elixir
@spec delete_group(Celery.t() | Celery.Config.t(), String.t()) :: :ok
```

Deletes group metadata from `celery-taskset-meta-<group_id>`.

# `encode_result_meta`

```elixir
@spec encode_result_meta(
  Celery.t() | Celery.Config.t(),
  String.t(),
  term(),
  String.t(),
  keyword()
) :: {:ok, String.t(), map()} | {:error, term()}
```

Encodes a task result metadata dictionary into the exact JSON format stored in Redis
by Python Celery.

# `exception_to_elixir`

```elixir
@spec exception_to_elixir(term(), String.t() | nil) :: Exception.t()
```

Converts a stored exception dictionary (`%{"exc_type" => ..., "exc_message" => ..., "exc_module" => ...}`)
into an Elixir exception struct (`%Celery.RemoteError{}` or `%Celery.TaskRevokedError{}`).

# `forget`

```elixir
@spec forget(Celery.t() | Celery.Config.t(), String.t()) :: :ok
```

Deletes the task's result metadata from Redis.

# `get_key_for_chord`

```elixir
@spec get_key_for_chord(Celery.t() | Celery.Config.t(), String.t(), String.t()) ::
  String.t()
```

Returns the Redis key for a chord ID (`"chord-unlock-<group_id>"`).

# `get_key_for_group`

```elixir
@spec get_key_for_group(Celery.t() | Celery.Config.t(), String.t(), String.t()) ::
  String.t()
```

Returns the Redis key for a group/taskset ID (`"celery-taskset-meta-<group_id>"`).

# `get_key_for_task`

```elixir
@spec get_key_for_task(Celery.t() | Celery.Config.t(), String.t(), String.t()) ::
  String.t()
```

Returns the Redis key for a task ID (`"celery-task-meta-<task_id>"`, prefixed with
`global_keyprefix` if configured).

# `get_many`

```elixir
@spec get_many(Celery.t() | Celery.Config.t(), [String.t()]) :: %{
  required(String.t()) =&gt; map()
}
```

Fetches metadata for multiple task IDs in a single `MGET` call.

# `get_result`

```elixir
@spec get_result(Celery.t() | Celery.Config.t(), String.t()) :: term()
```

Returns the task result (or reconstructed `%Celery.RemoteError{}` if failed).

# `get_state`

```elixir
@spec get_state(Celery.t() | Celery.Config.t(), String.t()) :: String.t()
```

Returns the current task state (`"PENDING"`, `"SUCCESS"`, `"FAILURE"`, etc.).

# `get_task_meta`

```elixir
@spec get_task_meta(Celery.t() | Celery.Config.t(), String.t()) :: map()
```

Fetches the decoded task metadata dictionary from Redis.
If the task does not exist in Redis, returns `%{"status" => "PENDING", "result" => nil}`.

# `get_traceback`

```elixir
@spec get_traceback(Celery.t() | Celery.Config.t(), String.t()) :: String.t() | nil
```

Returns the task traceback string (or `nil`).

# `mark_as_done`

```elixir
@spec mark_as_done(Celery.t() | Celery.Config.t(), String.t(), term(), keyword()) ::
  {:ok, term()} | {:error, term()}
```

Marks a task as `SUCCESS` in the result backend and triggers chord completion if the
request is part of a chord.

# `mark_as_failure`

```elixir
@spec mark_as_failure(Celery.t() | Celery.Config.t(), String.t(), term(), keyword()) ::
  {:ok, term()} | {:error, term()}
```

Marks a task as `FAILURE` in the result backend, triggers chord failure handling if part
of a chord, propagates failure down any attached chain, and invokes errbacks.

# `mark_as_retry`

```elixir
@spec mark_as_retry(Celery.t() | Celery.Config.t(), String.t(), term(), keyword()) ::
  {:ok, term()} | {:error, term()}
```

Marks a task as `RETRY` in the result backend.

# `mark_as_revoked`

```elixir
@spec mark_as_revoked(
  Celery.t() | Celery.Config.t(),
  String.t(),
  String.t(),
  keyword()
) ::
  {:ok, term()} | {:error, term()}
```

Marks a task as `REVOKED` in the result backend.

# `mark_as_started`

```elixir
@spec mark_as_started(Celery.t() | Celery.Config.t(), String.t(), map(), keyword()) ::
  {:ok, term()} | {:error, term()}
```

Marks a task as `STARTED` in the result backend (`meta` typically includes `%{pid: ..., hostname: ...}`).

# `on_chord_part_return`

```elixir
@spec on_chord_part_return(
  Celery.t() | Celery.Config.t(),
  Celery.Task.Context.t(),
  String.t(),
  term()
) ::
  :ok
```

Handles completion of a chord header part (`on_chord_part_return` in `celery/backends/redis.py`).

Records `[1, task_id, state, encoded_result]` in `celery-taskset-meta-<gid>.j` (using `ZADD`
when `result_chord_ordered` is true and `group_index` is present, or `RPUSH` otherwise) and
triggers the chord callback once all parts have completed.

# `prepare_exception`

```elixir
@spec prepare_exception(term()) :: map()
```

Serializes an Elixir exception or error term into Python Celery's JSON exception dictionary:
`%{"exc_type" => ..., "exc_message" => [...], "exc_module" => ...}`.

# `restore_group`

```elixir
@spec restore_group(Celery.t() | Celery.Config.t(), String.t()) :: map() | nil
```

Restores group result metadata from `celery-taskset-meta-<group_id>`.

# `save_group`

```elixir
@spec save_group(Celery.t() | Celery.Config.t(), String.t(), map()) ::
  :ok | {:error, term()}
```

Saves group result metadata under `celery-taskset-meta-<group_id>`.

# `set_chord_size`

```elixir
@spec set_chord_size(Celery.t() | Celery.Config.t(), String.t(), non_neg_integer()) ::
  :ok
```

Sets the expected chord size in Redis (`celery-taskset-meta-<group_id>.s`), matching
Python Celery's `RedisBackend.set_chord_size/2`.

# `store_result`

```elixir
@spec store_result(
  Celery.t() | Celery.Config.t(),
  String.t(),
  term(),
  String.t(),
  keyword()
) :: {:ok, term()} | {:error, term()}
```

Stores task state and result in Redis and publishes the metadata to the task's
Redis Pub/Sub channel (`SETEX key expires value` + `PUBLISH key value`).

Matches Python Celery's deduplication behavior: if the existing state in Redis is
already `"SUCCESS"`, does not overwrite it.

# `wait_for`

```elixir
@spec wait_for(Celery.t() | Celery.Config.t(), String.t(), keyword()) :: term()
```

Waits for a task to reach one of `States.ready_states()` (`SUCCESS`, `FAILURE`, `REVOKED`),
returning the result or raising if `propagate: true` (default) and the task failed/revoked.

Options:
- `:timeout` - timeout in milliseconds or seconds (float, e.g. `5.0`, or integer ms `5000`, or `:infinity`; default `:infinity`)
- `:interval` - polling interval in milliseconds (default `50`)
- `:propagate` - whether to raise on `FAILURE` / `REVOKED` (default `true`)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
