Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to change timeout when performing batch inserts #4

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions lib/cacheman.ex
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ defmodule Cacheman do
dashboard
end)

2. Timeouts:

By default, every redis command has to execute in 5 seconds. If there is a need
for longer timeout, it can be passed as:

{:ok, entry} = Cacheman.put_batch(:app, [{key, value}, ...], timeout: 20_000)

2. Get a key:

{:ok, entry} = Cacheman.get(:app, "user-dashboard")
Expand Down Expand Up @@ -81,8 +88,8 @@ defmodule Cacheman do
use GenServer
require Logger

@default_global_options [timeout: 5_000]
@default_put_options [ttl: :infinity]

#
# Cacheman API
#
Expand Down Expand Up @@ -148,12 +155,15 @@ defmodule Cacheman do
Where in the previous example, the cache key will be storred for 5 minutes.

Nil values are not storrable in the cache.

"""
def put(name, key, value, put_opts \\ @default_put_options) do
def put(name, key, value, opts \\ []) do
opts = (@default_put_options ++ @default_global_options) |> Keyword.merge(opts)

if value == nil do
{:ok, nil}
else
GenServer.call(full_process_name(name), {:put, key, value, put_opts})
GenServer.call(full_process_name(name), {:put, key, value, opts}, opts[:timeout])
end
end

Expand All @@ -173,8 +183,10 @@ defmodule Cacheman do
@spec put_batch(String.t(), list(key_value_pair), list()) ::
{:ok, integer}
| {:error, Redix.Protocol.ParseError | Redix.Error | Redix.ConnectionError}
def put_batch(name, key_value_pairs, put_opts \\ @default_put_options) do
GenServer.call(full_process_name(name), {:put_batch, key_value_pairs, put_opts})
def put_batch(name, key_value_pairs, opts \\ []) do
opts = (@default_put_options ++ @default_global_options) |> Keyword.merge(opts)

GenServer.call(full_process_name(name), {:put_batch, key_value_pairs, opts}, opts[:timeout])
end

@doc """
Expand Down Expand Up @@ -306,6 +318,8 @@ defmodule Cacheman do
end

def handle_call({:put_batch, key_value_pairs, put_opts}, _from, opts) do
Logger.debug("[Cacheman] OPTS: #{inspect(put_opts)}")

response =
apply(opts.backend_module, :put_batch, [
opts.backend_pid,
Expand Down
38 changes: 24 additions & 14 deletions lib/cacheman/backend/redis.ex
Original file line number Diff line number Diff line change
Expand Up @@ -41,24 +41,34 @@ defmodule Cacheman.Backend.Redis do
end)
end

def put(conn, key, value, ttl) do
:poolboy.transaction(conn, fn c ->
case Redix.command(c, ["SET", key, value] ++ ttl_command(ttl)) do
{:ok, "OK"} -> {:ok, value}
e -> e
end
end)
def put(conn, key, value, opts) do
:poolboy.transaction(
conn,
fn c ->
case Redix.command(c, ["SET", key, value] ++ ttl_command(opts[:ttl]),
timeout: opts[:timeout]
) do
{:ok, "OK"} -> {:ok, value}
e -> e
end
end,
opts[:timeout]
)
end

def put_batch(conn, key_value_pairs, ttl) when is_list(key_value_pairs) do
def put_batch(conn, key_value_pairs, opts) when is_list(key_value_pairs) do
list_of_commands =
Enum.map(key_value_pairs, fn {key, value} ->
["SET", key, value] ++ ttl_command(ttl)
["SET", key, value] ++ ttl_command(opts[:ttl])
end)

:poolboy.transaction(conn, fn c ->
Redix.pipeline(c, list_of_commands)
end)
:poolboy.transaction(
conn,
fn c ->
Redix.pipeline(c, list_of_commands, timeout: opts[:timeout])
end,
opts[:timeout]
)
end

def delete(conn, keys) do
Expand All @@ -73,6 +83,6 @@ defmodule Cacheman.Backend.Redis do
end)
end

def ttl_command(ttl: :infinity), do: []
def ttl_command(ttl: ttl), do: ["PX", "#{ttl}"]
def ttl_command(:infinity), do: []
VeljkoMaksimovic marked this conversation as resolved.
Show resolved Hide resolved
def ttl_command(ttl), do: ["PX", "#{ttl}"]
end
1 change: 1 addition & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ defmodule ExCacheman.MixProject do
defp deps do
[
{:redix, "~> 0.10.5"},
{:mock, "~> 0.3.0", only: :test},
{:poolboy, "~> 1.5"}
]
end
Expand Down
2 changes: 2 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
%{
"meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"},
"mock": {:hex, :mock, "0.3.7", "75b3bbf1466d7e486ea2052a73c6e062c6256fb429d6797999ab02fa32f29e03", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "4da49a4609e41fd99b7836945c26f373623ea968cfb6282742bcb94440cf7e5c"},
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
"redix": {:hex, :redix, "0.10.5", "2240a74cc0a236e0e0d8ebf2d20674151d59e9965342879d36cf856d93099f01", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "37774c9753a4b3bb7cb263b5996357ffc319129c70bb698f5cc02d676c704b81"},
"telemetry": {:hex, :telemetry, "0.4.1", "ae2718484892448a24470e6aa341bc847c3277bfb8d4e9289f7474d752c09c7f", [:rebar3], [], "hexpm", "4738382e36a0a9a2b6e25d67c960e40e1a2c95560b9f936d8e29de8cd858480f"},
Expand Down
25 changes: 25 additions & 0 deletions test/cacheman_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
defmodule CachemanTest do
use ExUnit.Case
import Mock
doctest Cacheman

setup_all do
Expand Down Expand Up @@ -72,6 +73,18 @@ defmodule CachemanTest do
assert {:ok, nil} = Cacheman.get(:good, key2)
end

test "put_batch with custom timeout" do
timeout = 10_000

with_mock Redix, [],
pipeline: fn _, _, opts ->
:timer.sleep(trunc(timeout * 0.7))
assert opts[:timeout] == timeout
end do
assert Cacheman.put_batch(:good, [{"test_key", "test_value"}], timeout: timeout)
end
end

test "get_batch" do
key1 = "test-#{:rand.uniform(10_000)}"
key2 = "test-#{:rand.uniform(10_000)}"
Expand Down Expand Up @@ -171,6 +184,18 @@ defmodule CachemanTest do
assert {:ok, nil} = Cacheman.get(:good, key2)
end

test "put_batch with custom timeout excided" do
timeout = 10_000

with_mock Redix, [],
pipeline: fn _, _, opts ->
assert opts[:timeout] == timeout
:timer.sleep(trunc(timeout * 1.2))
end do
catch_exit(Cacheman.put_batch(:broken, [{"test_key", "test_value"}], timeout: timeout))
end
end

test "get_batch" do
key1 = "test-#{:rand.uniform(10_000)}"
key2 = "test-#{:rand.uniform(10_000)}"
Expand Down