Packages
honeydew
0.0.2
1.5.0
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.0
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
1.0.0-rc7
1.0.0-rc6
1.0.0-rc5
1.0.0-rc4
1.0.0-rc3
1.0.0-rc2
1.0.0-rc1
0.0.11
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.3
0.0.2
0.0.1
Pluggable local/clusterable job queue focused on safety.
Current section
Files
Jump to
Current section
Files
README.md
Honeydew
========
Honeydew (["Honey, do!"](http://en.wiktionary.org/wiki/honey_do_list)) is a job queue + worker pool for Elixir.
- Workers are permanent and hold immutable state.
- Workers pull jobs from the work queue.
- Tasks are executed using `cast/2` and `call/2`, somewhat like a `GenServer`.
- If a worker crashes while processing a job, the job is recovered and placed back on the queue.
## Usage
Create a worker module and `use Honeydew`, then start the pool in your supervision tree with `Honeydew.child_spec/4`.
Honeydew will call your worker's `init/1` and will keep the state from `{:ok, state}`.
You can add tasks to the queue using `cast/2` or `call/2`, like so:
`Database.cast(:poolname, {:put, ["key", "value"]})`
`Database.call(:poolname, :up?)`
## Example
```elixir
defmodule Riak do
use Honeydew
@moduledoc """
This is an example Worker to interface with Riak.
You'll need to add the erlang riak driver to your mix.exs:
`{:riakc, github: "basho/riak-erlang-client"}`
"""
def init({ip, port}) do
:riakc_pb_socket.start_link(ip, port)
end
def up?(riak) do
:riakc_pb_socket.ping(riak) == :pong
end
def put(bucket, key, obj, content_type, riak) do
:riakc_pb_socket.put(riak, :riakc_obj.new(bucket, key, obj, content_type))
end
def get(bucket, key, riak) do
case :riakc_pb_socket.get(riak, bucket, key) do
{:ok, obj} -> :riakc_obj.get_value(obj)
{:error, :notfound} -> nil
error -> error
end
end
end
```
Add the pool to your application's supervision tree:
```elixir
def start(_type, _args) do
import Supervisor.Spec, warn: false
children = [
Honeydew.child_spec(:riak_pool, Riak, {'127.0.0.1', 8087})
]
Supervisor.start_link(children, strategy: :one_for_one))
end
```
```elixir
iex(1)> Riak.call(:riak_pool, :up?)
true
iex(2)> Riak.cast(:riak_pool, {:put, ["bucket", "key", "value", "text/plain"]})
:ok
iex(3)> Riak.call(:riak_pool, {:get, ["bucket", "key"]})
"value"
```
## Worker State
Worker state is immutable, the only way to change it is to cause the worker to crash and let the supervisor restart it.
Your worker module's `init/1` function must return `{:ok, state}`. If anything else is returned or the function raises an error, the worker will die and restart after a given time interval (by default, five seconds).
## Pool Options
`Honeydew.child_spec/4`'s last argument is a keyword list of pool options.
See the [Honeydew](https://github.com/koudelka/honeydew/blob/master/lib/honeydew.ex) module for the possible options.
## Process Tree
```
Honeydew.Supervisor
├── Honeydew.WorkQueue
└── Honeydew.WorkerSupervisor
└── Honeydew.Worker (x 10, by default)
```
## TODO:
- Failure backends
- :abandon
- :requeue
- delay interval
- action after max_tries (abandon, keep in queue, marshal)
- Distribution
- jobs in mnesia, to allow other nodes to run work queues?
## Acknowledgements
Thanks to @marcelog, for his [failing worker restart strategy](http://inaka.net/blog/2012/11/29/every-day-erlang/).