View Source OddJob (OddJob v0.2.1)

Job pools for Elixir OTP applications, written in Elixir.

Usage

You can add job pools directly to the top level of your own application's supervision tree:

defmodule MyApp.Application do
  use Application

  def start(_type, _args) do

    children = [
      {OddJob, :email},
      {OddJob, :task}
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

The tuple {OddJob, :email} will return a child spec for a supervisor that will start and supervise the :email pool. The second element of the tuple can be any atom that you want to use as a unique name for the pool.

You can also configure OddJob to supervise your pools for you in a separate supervision tree.

In your config.exs:

config :odd_job,
  supervise: [:email, :task]

You can also configure a custom pool size that will apply to all pools:

config :odd_job, pool_size: 10 # the default value is 5

Now you can call on your pools to perform concurrent fire and forget jobs:

OddJob.perform(:email, fn -> send_confirmation_email() end)
OddJob.perform(:task, fn -> update_external_application() end)

Link to this section Summary

Functions

Performs an async job that can be awaited on for the result.

Awaits on an async job and returns the results.

Awaits replies form multiple async jobs and returns them in a list.

Performs a fire and forget job.

Adds a job to the queue of the job pool after the given timer has elapsed.

Adds a job to the queue of the job pool at the given time.

Returns the pid and state of the job pool's queue.

Returns the ID of the job pool's queue.

Returns the pid of the job pool's supervisor.

Returns the ID of the job pool's supervisor.

Returns a list of pids for the specified worker pool.

Link to this section Types

Specs

child_spec() :: %{
  id: atom(),
  start: {OddJob.Supervisor, :start_link, [atom()]},
  type: :supervisor
}

Specs

job() :: OddJob.Job.t()

Specs

queue() :: OddJob.Queue.t()

Link to this section Functions

Link to this function

async_perform(pool, fun)

View Source

Specs

async_perform(atom(), function()) :: job()

Performs an async job that can be awaited on for the result.

Functions like Task.async/1 and Task.await/2.

Examples

iex> job = OddJob.async_perform(:work, fn -> :math.exp(100) end)
iex> OddJob.await(job)
2.6881171418161356e43
Link to this function

await(job, timeout \\ 5000)

View Source

Specs

await(job(), timeout()) :: any()

Awaits on an async job and returns the results.

Examples

iex> OddJob.async_perform(:work, fn -> :math.log(2.6881171418161356e43) end)
...> |> OddJob.await()
100.0
Link to this function

await_many(jobs, timeout \\ 5000)

View Source

Specs

await_many([job()], timeout()) :: [any()]

Awaits replies form multiple async jobs and returns them in a list.

This function receives a list of jobs and waits for their replies in the given time interval. It returns a list of the results, in the same order as the jobs supplied in the jobs input argument.

If any of the job worker processes dies, the caller process will exit with the same reason as that worker.

A timeout, in milliseconds or :infinity, can be given with a default value of 5000. If the timeout is exceeded, then the caller process will exit. Any worker processes that are linked to the caller process (which is the case when a job is started with async_perform/2) will also exit.

This function assumes the jobs' monitors are still active or the monitor's :DOWN message is in the message queue. If any jobs have been demonitored, or the message already received, this function will wait for the duration of the timeout.

Examples

iex> job1 = OddJob.async_perform(:work, fn -> 2 ** 2 end)
iex> job2 = OddJob.async_perform(:work, fn -> 3 ** 2 end)
iex> [job1, job2] |> OddJob.await_many()
[4, 9]

Specs

perform(atom(), function()) :: :ok

Performs a fire and forget job.

Examples

iex> parent = self()
iex> :ok = OddJob.perform(:work, fn -> send(parent, :hello) end)
iex> receive do
...>   msg -> msg
...> end
:hello
Link to this function

perform_after(timer, pool, fun)

View Source

Specs

perform_after(integer(), atom(), function()) :: reference()

Adds a job to the queue of the job pool after the given timer has elapsed.

timer is an integer that indicates the number of milliseconds that should elapse before the job enters the queue. The timed message is executed under a separate supervised process, so if the caller crashes the job will still be performed. A timer reference is returned, which can be read with Process.read_timer/1 or canceled with Process.cancel_timer/1.

Examples

timer_ref = OddJob.perform_after(5000, :work, fn -> deferred_job() end)
Process.read_timer(timer_ref)
#=> 2836 # time remaining before job enters the queue
Process.cancel_timer(timer_ref)
#=> 1175 # job has been cancelled

timer_ref = OddJob.perform_after(5000, :work, fn -> deferred_job() end)
Process.sleep(6000)
Process.cancel_timer(timer_ref)
#=> false # too much time has passed to cancel the job
Link to this function

perform_at(time, pool, fun)

View Source

Specs

perform_at(Time.t() | DateTime.t(), atom(), function()) :: reference()

Adds a job to the queue of the job pool at the given time.

time can be a Time or a DateTime struct. If a Time struct is received, then the job will be done the next time the clock strikes the given time. The timed message is executed under a separate supervised process, so if the caller crashes the job will still be performed. A timer reference is returned, which can be read with Process.read_timer/1 or canceled with Process.cancel_timer/1.

Examples

time = Time.utc_now() |> Time.add(600, :second)
OddJob.perform_at(time, :work, fn -> scheduled_job() end)

Specs

queue(atom()) :: {pid(), queue()}

Returns the pid and state of the job pool's queue.

Examples

iex> {pid, %OddJob.Queue{id: id}} = OddJob.queue(:work)
iex> is_pid(pid)
true
iex> id
:odd_job_work_queue

Specs

queue_id(atom()) :: atom()

Returns the ID of the job pool's queue.

Examples

iex> OddJob.queue_id(:work)
:odd_job_work_queue

Specs

supervisor(atom()) :: pid()

Returns the pid of the job pool's supervisor.

There is no guarantee that the process will still be alive after the results are returned, as it could exit or be killed or restarted at any time. Use supervisor_id/1 to obtain the persistent ID of the supervisor.

Examples

OddJob.supervisor(:work)
#=> #PID<0.239.0>

Specs

supervisor_id(atom()) :: atom()

Returns the ID of the job pool's supervisor.

Examples

iex> OddJob.supervisor_id(:work)
:odd_job_work_sup

Specs

workers(atom()) :: [pid()]

Returns a list of pids for the specified worker pool.

There is no guarantee that the processes will still be alive after the results are returned, as they could exit or be killed at any time.

Examples

OddJob.workers(:work)
#=> [#PID<0.105.0>, #PID<0.106.0>, #PID<0.107.0>, #PID<0.108.0>, #PID<0.109.0>]