Skip to content

Instantly share code, notes, and snippets.

@hodak
Created December 6, 2016 07:15
Show Gist options
  • Save hodak/300c27f54a0a2809b5f7541e878a772c to your computer and use it in GitHub Desktop.
Save hodak/300c27f54a0a2809b5f7541e878a772c to your computer and use it in GitHub Desktop.
defmodule WebDAVWorker do
use GenServer
# Client
def start_link do
GenServer.start_link(__MODULE__, [])
end
def run_action(pid, action_handler, args \\ [], delay \\ 0) do
GenServer.call(pid, {:run_action, action_handler, args, delay})
end
# Server
def handle_call({:run_action, action_handler, args, delay}, from, actions) do
Process.send_after(self, :try_running, delay)
action = {action_handler, args, from}
{:noreply, [action | actions]}
end
def handle_info(:try_running, []) do
{:noreply, []}
end
def handle_info(:try_running, [{action_handler, _, _} | _] = actions) do
relevant_action? = fn({handler, _, _}) -> action_handler == handler end
relevant_actions = Enum.filter(actions, relevant_action?)
relevant_actions_args = Enum.map(relevant_actions, fn({_, arg, _}) -> arg end)
response = action_handler.(relevant_actions_args)
Enum.each(relevant_actions, fn({_, _, from}) -> GenServer.reply(from, response) end)
{:noreply, Enum.reject(actions, relevant_action?)}
end
end
defmodule WebDAVWorkerTest do
use ExUnit.Case
alias WebDAVWorker
setup do
{:ok, pid} = WebDAVWorker.start_link
[worker_pid: pid]
end
test "it runs action and returns its result", %{worker_pid: pid} do
action = fn(_) -> :ok end
assert :ok == WebDAVWorker.run_action(pid, action)
end
test "it receives an argument and passes it to handler as a list", %{worker_pid: pid} do
action = fn(arg) -> arg end
assert [:hodor] == WebDAVWorker.run_action(pid, action, :hodor)
end
test "it squashes actions and calls handler once with all the arguments", %{worker_pid: pid} do
self_pid = self
action = fn(args) -> send self_pid, args end
Enum.each([:a, :b], fn(arg) -> spawn fn -> WebDAVWorker.run_action(pid, action, arg, 1) end end)
assert_receive [:b, :a]
end
test "it squashes actions with the same handler", %{worker_pid: pid} do
self_pid = self
h1 = fn(args) -> send self_pid, args end
h2 = fn(args) -> send self_pid, args end
[{h1, :a}, {h2, :b}, {h1, :c}, {h2, :d}]
|> Enum.each(fn({handler, arg}) -> spawn fn -> WebDAVWorker.run_action(pid, handler, arg, 1) end end)
assert_receive [:c, :a]
assert_receive [:d, :b]
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment