# `BullMQ.Types`
[🔗](https://github.com/taskforcesh/bullmq/blob/v2.2.3/lib/bullmq/types.ex#L1)

Type definitions for BullMQ.

This module defines the core types used throughout the BullMQ library.
All types are designed to be compatible with the Node.js BullMQ library.

# `backoff_opts`

```elixir
@type backoff_opts() :: %{
  optional(:type) =&gt; backoff_type(),
  optional(:delay) =&gt; duration_ms(),
  optional(:jitter) =&gt; float()
}
```

Backoff configuration.

# `backoff_type`

```elixir
@type backoff_type() :: :fixed | :exponential | atom()
```

Backoff strategy type.

# `deduplication_opts`

```elixir
@type deduplication_opts() :: %{
  :id =&gt; String.t(),
  optional(:ttl) =&gt; duration_ms(),
  optional(:extend) =&gt; boolean(),
  optional(:replace) =&gt; boolean(),
  optional(:keep_last_if_active) =&gt; boolean()
}
```

Deduplication options.

## Modes

- **Simple Mode**: Only `:id` is provided. Jobs are deduplicated until completion or failure.
- **Throttle Mode**: `:id` and `:ttl` provided. Jobs are deduplicated for the TTL duration.
- **Debounce Mode**: `:id`, `:ttl`, `:extend`, and `:replace` all set. Each new job
  with the same ID extends the TTL and replaces the existing job data.

## Options

- `:id` - (required) Unique identifier for deduplication
- `:ttl` - Time-to-live in milliseconds for the deduplication key
- `:extend` - If true, extend the TTL on each duplicate job
- `:replace` - If true, replace the job data when a duplicate is added (while delayed)

# `duration_ms`

```elixir
@type duration_ms() :: non_neg_integer()
```

Duration in milliseconds.

# `error_reason`

```elixir
@type error_reason() :: atom() | String.t() | Exception.t()
```

Error reason.

# `fail_parent_on_failure`

```elixir
@type fail_parent_on_failure() :: boolean()
```

Worker failure behavior for parent jobs.

# `finished_status`

```elixir
@type finished_status() :: :completed | :failed
```

Finished job states.

# `ignore_dependency`

```elixir
@type ignore_dependency() :: boolean()
```

Ignore dependency behavior.

# `job_data`

```elixir
@type job_data() :: map() | list() | String.t() | number() | boolean() | nil
```

Job data payload. Can be any JSON-serializable term.

# `job_id`

```elixir
@type job_id() :: String.t()
```

Job identifier, typically a string representation of an integer or UUID.

# `job_json`

```elixir
@type job_json() :: %{
  :id =&gt; job_id(),
  :name =&gt; job_name(),
  :data =&gt; String.t(),
  :opts =&gt; String.t(),
  :timestamp =&gt; timestamp_ms(),
  optional(:delay) =&gt; duration_ms(),
  optional(:priority) =&gt; priority(),
  optional(:processedOn) =&gt; timestamp_ms(),
  optional(:finishedOn) =&gt; timestamp_ms(),
  optional(:progress) =&gt; String.t(),
  optional(:returnvalue) =&gt; String.t(),
  optional(:failedReason) =&gt; String.t(),
  optional(:stacktrace) =&gt; String.t(),
  optional(:attemptsMade) =&gt; non_neg_integer(),
  optional(:attemptsStarted) =&gt; non_neg_integer(),
  optional(:stalledCounter) =&gt; non_neg_integer(),
  optional(:parentKey) =&gt; String.t(),
  optional(:parent) =&gt; String.t(),
  optional(:processedBy) =&gt; String.t(),
  optional(:rjk) =&gt; String.t(),
  optional(:deid) =&gt; String.t(),
  optional(:df) =&gt; String.t()
}
```

Job JSON representation for Redis storage.

# `job_name`

```elixir
@type job_name() :: String.t()
```

Job name/type identifier.

# `job_opts`

```elixir
@type job_opts() :: %{
  optional(:job_id) =&gt; job_id() | nil,
  optional(:priority) =&gt; priority(),
  optional(:delay) =&gt; duration_ms(),
  optional(:attempts) =&gt; pos_integer(),
  optional(:backoff) =&gt; backoff_opts(),
  optional(:lifo) =&gt; boolean(),
  optional(:timeout) =&gt; duration_ms(),
  optional(:remove_on_complete) =&gt; keep_jobs(),
  optional(:remove_on_fail) =&gt; keep_jobs(),
  optional(:timestamp) =&gt; timestamp_ms(),
  optional(:parent) =&gt; parent_opts(),
  optional(:repeat) =&gt; repeat_opts(),
  optional(:deduplication) =&gt; deduplication_opts(),
  optional(:fail_parent_on_failure) =&gt; fail_parent_on_failure(),
  optional(:ignore_dependency) =&gt; ignore_dependency(),
  optional(:remove_dependency) =&gt; remove_dependency(),
  optional(:telemetry_metadata) =&gt; String.t(),
  optional(:omit_context) =&gt; boolean()
}
```

Job options for adding a job to the queue.

# `job_progress`

```elixir
@type job_progress() :: number() | map()
```

Job progress value - either a number (0-100) or custom progress data.

# `job_return_value`

```elixir
@type job_return_value() :: term()
```

Job return value after processing.

# `job_state`

```elixir
@type job_state() ::
  :waiting
  | :active
  | :delayed
  | :prioritized
  | :completed
  | :failed
  | :waiting_children
  | :unknown
```

Job state in the queue.

# `keep_jobs`

```elixir
@type keep_jobs() ::
  boolean()
  | non_neg_integer()
  | %{age: duration_ms()}
  | %{count: non_neg_integer()}
```

Job removal configuration.
- `true` - Remove immediately after completion/failure
- `false` - Never remove
- positive integer - Remove after this many milliseconds
- `%{age: ms}` - Remove after job is older than this
- `%{count: n}` - Keep only the last n jobs

# `lock_token`

```elixir
@type lock_token() :: String.t()
```

Token used for job locking.

# `metrics_opts`

```elixir
@type metrics_opts() :: %{optional(:max_data_points) =&gt; pos_integer()}
```

Metrics options.

# `parent_opts`

```elixir
@type parent_opts() :: %{
  :id =&gt; job_id(),
  :queue =&gt; queue_name(),
  optional(:prefix) =&gt; String.t()
}
```

Parent job reference options.

# `priority`

```elixir
@type priority() :: non_neg_integer()
```

Priority level (0 = highest priority).

# `processor_result`

```elixir
@type processor_result() ::
  {:ok, job_return_value()}
  | :ok
  | {:error, term()}
  | {:delay, duration_ms()}
  | {:rate_limit, duration_ms()}
  | :waiting
  | :waiting_children
```

Processor result type.

Processors can return various tagged tuples to control job flow:

- `{:ok, result}` - Job completed successfully with result
- `:ok` - Job completed successfully (no result)
- `{:error, reason}` - Job failed with error
- `{:delay, milliseconds}` - Move job to delayed queue (does not increment attempts)
- `{:rate_limit, milliseconds}` - Move job back to wait and pause worker for duration
- `:waiting` - Move job back to waiting queue
- `:waiting_children` - Move job to waiting-children state (wait for child jobs)

# `queue_event`

```elixir
@type queue_event() ::
  :added
  | :waiting
  | :active
  | :progress
  | :completed
  | :failed
  | :delayed
  | :stalled
  | :removed
  | :drained
  | :paused
  | :resumed
  | :duplicated
  | :deduplicated
  | :retries_exhausted
  | :waiting_children
  | :cleaned
```

Queue event types.

# `queue_name`

```elixir
@type queue_name() :: String.t()
```

Queue name.

# `queue_opts`

```elixir
@type queue_opts() :: %{
  optional(:prefix) =&gt; String.t(),
  optional(:default_job_opts) =&gt; job_opts(),
  optional(:settings) =&gt; queue_settings(),
  optional(:telemetry) =&gt; module()
}
```

Queue options.

# `queue_settings`

```elixir
@type queue_settings() :: %{
  optional(:stalled_interval) =&gt; duration_ms(),
  optional(:max_stalled_count) =&gt; non_neg_integer(),
  optional(:lock_duration) =&gt; duration_ms()
}
```

Queue settings.

# `rate_limiter_opts`

```elixir
@type rate_limiter_opts() :: %{
  :max =&gt; pos_integer(),
  :duration =&gt; duration_ms(),
  optional(:group_key) =&gt; String.t()
}
```

Rate limiter configuration.

# `redis_connection`

```elixir
@type redis_connection() ::
  atom()
  | pid()
  | {:dedicated, pid()}
  | {:via, module(), term()}
  | {atom(), node()}
```

Connection specification passed to the datastore backend. The concrete shape
is a backend concern (for the Redis backend it is a `BullMQ.RedisConnection`
reference or a raw client).

# `remove_dependency`

```elixir
@type remove_dependency() :: boolean()
```

Remove dependency behavior.

# `repeat_opts`

```elixir
@type repeat_opts() :: %{
  optional(:pattern) =&gt; String.t(),
  optional(:every) =&gt; duration_ms(),
  optional(:limit) =&gt; pos_integer(),
  optional(:start_date) =&gt; DateTime.t() | timestamp_ms(),
  optional(:end_date) =&gt; DateTime.t() | timestamp_ms(),
  optional(:tz) =&gt; String.t(),
  optional(:immediately) =&gt; boolean(),
  optional(:offset) =&gt; duration_ms(),
  optional(:count) =&gt; non_neg_integer()
}
```

Repeat/scheduling options.

# `result`

```elixir
@type result(ok_type) :: {:ok, ok_type} | {:error, error_reason()}
```

Result type with error.

# `timestamp_ms`

```elixir
@type timestamp_ms() :: non_neg_integer()
```

Timestamp in milliseconds since Unix epoch.

# `worker_opts`

```elixir
@type worker_opts() :: %{
  optional(:name) =&gt; atom() | String.t(),
  optional(:concurrency) =&gt; pos_integer(),
  optional(:lock_duration) =&gt; duration_ms(),
  optional(:lock_renew_time) =&gt; duration_ms(),
  optional(:stalled_interval) =&gt; duration_ms(),
  optional(:max_stalled_count) =&gt; non_neg_integer(),
  optional(:drain_delay) =&gt; duration_ms(),
  optional(:limiter) =&gt; rate_limiter_opts(),
  optional(:skip_stalled_check) =&gt; boolean(),
  optional(:remove_on_complete) =&gt; keep_jobs(),
  optional(:remove_on_fail) =&gt; keep_jobs(),
  optional(:autorun) =&gt; boolean(),
  optional(:prefix) =&gt; String.t(),
  optional(:metrics) =&gt; metrics_opts(),
  optional(:telemetry) =&gt; module(),
  optional(:on_completed) =&gt; (term(), term() -&gt; any()),
  optional(:on_failed) =&gt; (term(), String.t() -&gt; any()),
  optional(:on_error) =&gt; (term() -&gt; any()),
  optional(:on_active) =&gt; (term() -&gt; any()),
  optional(:on_progress) =&gt; (term(), term() -&gt; any()),
  optional(:on_stalled) =&gt; (String.t() -&gt; any()),
  optional(:on_lock_renewal_failed) =&gt; ([String.t()] -&gt; any())
}
```

Worker options.

Most options have sensible defaults and don't need to be changed:

- `:lock_duration` - Default: 30,000ms. Time before a job lock expires. Should normally
  not be changed unless you have jobs that legitimately take longer than 30 seconds
  between progress updates.

- `:stalled_interval` - Default: 30,000ms. How often to check for stalled jobs. Should
  normally not be changed. Must be less than `:lock_duration`.

- `:max_stalled_count` - Default: 1. Number of times a job can stall before being moved
  to failed. We consider stalled jobs a rare occurrence, so stalling more than once
  typically indicates a more serious issue (e.g., worker crashes, resource exhaustion).
  Increasing this value is not recommended unless you have a specific use case.

---

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