# `FaktoryWorker.Job`
[🔗](https://github.com/opt-elixir/faktory_worker/blob/main/lib/faktory_worker/job.ex#L1)

The `FaktoryWorker.Job` module is used to perform jobs in the background by sending to and fetching from Faktory.

To build a worker you must `use` the job module within a module in your application.

```elixir
defmodule MyApp.SomeWorker do
  use FaktoryWorker.Job
end
```

This will bring in all of the functionality required to perform jobs via Faktory. The `MyApp.SomeWorker` will now
have a `perform_async/2` function available for sending jobs to Faktory. Before this function can be called, a
`perform` function must be defined. This function must accept the same number of arguments that are
being sent to Faktory via the `perform_async/2` function.

```elixir
defmodule MyApp.SomeWorker do
  use FaktoryWorker.Job

  def perform(job_arg) do
    do_some_work(job_arg)
  end
end
```

With this in place it is now possible to send work to Faktory and the `MyApp.SomeWorker` will fetch the job and call
the `perform/1` function with the same job arguments that we sent.

```elixir
> MyApp.SomeWorker.perform_async("job arg")
:ok
```

It is also possible to send multiple arguments for a single job by passing in a list of values to the `perform_async/2`
function.

```elixir
> MyApp.SomeWorker.perform_async(["job arg1", "job arg2"])
:ok
```

In order for the job to be performed correctly, a `perform/2` function needs to be defined within the `MyApp.SomeWorker`
module.

```elixir
defmodule MyApp.SomeWorker do
  use FaktoryWorker.Job

  def perform(job_arg1, job_arg2) do
    do_some_work(job_arg1, job_arg2)
  end
end
```

When defining `perform` functions, they must always accept one argument for each item in the list of values passed into
`perform_async/2`.

## Retrying jobs on failure

When a job fails, the Faktory server can enqueue it again to be retried. By default, a job is only considered
to have failed when it `raise`s an exception.

```elixir
def perform do
  raise "retry me!"
end
```

If you would like to consider the return value from `perform` and retry when an error is returned, you may enable
the `:retry_on_error` config option.

```elixir
# config.exs
config :my_app, FaktoryWorker, retry_on_error: true

# job.ex
def perform do
  case MyWorker.do_work() do
    # returning `:error` or `{:error, term()}` will retry the job
    # when `:retry_on_error` is set to `true`
    :error -> :error
    {:error, reason} -> {:error, reason}
    
    # raising will still retry the job, as well
    {:error, "fatal"} -> raise("oh no!")

    # returning anything else will be considered a success
    :ok -> :ok
    _ -> :something_else
  end
end
```

## Synchronous job pushing

Previous version used Broadway to send jobs and `:skip_pipeline` parameter was used to do it synchronously.
`:skip_pipeline` is not supported anymore.
Since Batch operations is a feature of Faktory Enterprise this library now sends any single job synchronously
and makes HTTP call to faktory server (see `FaktoryWorker.Batch`).

## Worker Configuration

A list of options can be specified when using the the `FaktoryWorker.Job` module. These options will be used when sending
jobs to faktory and will apply to all jobs sent with the `perform_async/2` function.

For a full list of configuration options see the [Worker Configuration](configuration.html#worker-configuration) documentation.

## Overriding Worker Configuration

The `perform_async/2` function accepts a keyword list as its second argument. This list has the same options
available that the `FaktoryWorker.Job` module accepts. Any options passed into this function override the options
that have been set on the worker module.

For a full list of configuration options see the [Worker Configuration](configuration.html#worker-configuration) documentation.

## Data Serialization

Faktory expects all values to be serialized in JSON format. FaktoryWorker uses `Jason` for serialization. This
means only values that implement the `Jason.Encoder` protocol are valid when calling the `perform_async/2` function.

---

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