# `Storehouse.Job`
[🔗](https://github.com/hattoriai/storehouse/blob/v0.2.0/lib/storehouse/job.ex#L1)

A piece of Storehouse's work done out of the request: a file's
analysis, a deletion, a mirror's copy. A runner keeps it and runs it
(`Storehouse.Runner`).

A job is a worker, a module of this behaviour, and its arguments, a map
JSON holds, so that any runner can keep it: in memory, in a database
(Oban), in a workflow engine. `to_map/1` gives a job as JSON holds it,
and `from_map/1` gives it back.

A runner calls `run/1` until it gives `:ok`, at most `:max_attempts`
times, then `discarded/3`.

## Telemetry

Each run is a span, `[:storehouse, :job, :start | :stop | :exception]`,
with the job's `:worker` and `:unique`, and `result: :ok | :error`;
a job given up is `[:storehouse, :job, :discarded]`, with
`%{attempts: n}` and the `:job` and the `:reason`.

# `t`

```elixir
@type t() :: %Storehouse.Job{
  args: map(),
  max_attempts: pos_integer(),
  unique: String.t(),
  worker: module()
}
```

# `perform`

```elixir
@callback perform(args :: map()) :: :ok | {:error, term()}
```

Does the job's work, with its arguments: `:ok`, or why it failed, to be tried again.

# `discarded`

```elixir
@spec discarded(t(), term(), pos_integer()) :: :ok
```

Tells that a runner gave the job up after `attempts`: a warning in the
log, and the event `[:storehouse, :job, :discarded]`.

# `from_map`

```elixir
@spec from_map(map()) :: {:ok, t()} | {:error, term()}
```

The job of a map `to_map/1` gave, or `{:error, {:not_a_worker, name}}`
when its worker is not a module of this behaviour, in this app.

# `new`

```elixir
@spec new(module(), map(), keyword()) :: t()
```

A job of `worker` with `args`, a map with string keys that JSON holds.

  * `:unique` - what makes two jobs one while one waits (a runner that
    can keeps one of them). The default is the worker and its arguments.
  * `:max_attempts` - how many times it is tried. The default is 10.

# `run`

```elixir
@spec run(t()) :: :ok | {:error, term()}
```

Runs the job once: `:ok`, or `{:error, reason}` for a runner to try it
again. A worker that raises gives its message as the reason.

# `to_map`

```elixir
@spec to_map(t()) :: map()
```

The job as JSON holds it, for a runner that keeps it out of memory.

---

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