Skip to content

Commit

Permalink
Merge pull request #141 from alexcastano/master
Browse files Browse the repository at this point in the history
Add custom retry time delay
  • Loading branch information
edgurgel authored Nov 18, 2017
2 parents 1d27a95 + 1de3b55 commit dc75f50
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 2 deletions.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,28 @@ This job can also be scheduled using `Verk.schedule/2`:
Verk.schedule(%Verk.Job{queue: :default, class: "ExampleWorker", args: [1,2]}, perform_at)
```

### Retry at

A job can define the function `retry_at/2` for custom retry time delay:

```elixir
defmodule ExampleWorker do
def perform(arg1, arg2) do
arg1 + arg2
end

def retry_at(failed_at, retry_count) do
failed_at + retry_count
end
end
```

In this example, the first retry will be scheduled a second later,
the second retry will be scheduled two seconds later, and so on.

If `retry_at/2` is not defined the default exponential backoff is used.


## Configuration

Example configuration for verk having 2 queues: `default` and `priority`
Expand Down
13 changes: 11 additions & 2 deletions lib/verk/retry_set.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ defmodule Verk.RetrySet do
"""
@spec add(%Job{}, integer, GenServer.server) :: :ok | {:error, Redix.Error.t}
def add(job, failed_at, redis \\ Verk.Redis) do
retry_at = calculate_retry_at(failed_at, job.retry_count)
retry_at = calculate_retry_at(job.class, failed_at, job.retry_count)
case Redix.command(redis, ["ZADD", @retry_key, to_string(retry_at), Poison.encode!(job)]) do
{:ok, _} -> :ok
{:error, error} -> {:error, error}
Expand All @@ -34,7 +34,16 @@ defmodule Verk.RetrySet do
bangify(add(job, failed_at, redis))
end

defp calculate_retry_at(failed_at, retry_count) do
defp calculate_retry_at(module_name, failed_at, retry_count) do
module = Module.safe_concat([module_name])
if :erlang.function_exported(module, :retry_at, 2) do
apply(module, :retry_at, [failed_at, retry_count])
else
default_calculate_retry_at(failed_at, retry_count)
end
end

defp default_calculate_retry_at(failed_at, retry_count) do
delay = :math.pow(retry_count, 4) + 15 + (:rand.uniform(30) * (retry_count + 1))
failed_at + delay
end
Expand Down
18 changes: 18 additions & 0 deletions test/retry_set_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ defmodule Verk.RetrySetTest do
import Verk.RetrySet
import :meck

defmodule DummyJob do
def retry_at(_failed_at, _retry_count) do
4
end
end

setup do
new [SortedSet, Redix]
:rand.seed(:exs1024, {123, 123534, 345345})
Expand All @@ -23,6 +29,18 @@ defmodule Verk.RetrySetTest do

assert validate [Poison, Redix]
end

test "allows custom retry_at" do
job = %Verk.Job{ class: "Verk.RetrySetTest.DummyJob", retry_count: 1 }
failed_at = 1
retry_at = "4"
expect(Poison, :encode!, [job], :payload)
expect(Redix, :command, [:redis, ["ZADD", "retry", retry_at, :payload]], { :ok, 1 })

assert add(job, failed_at, :redis) == :ok

assert validate [Poison, Redix]
end
end

describe "add!/3" do
Expand Down

0 comments on commit dc75f50

Please sign in to comment.