Awesome
Philosophy
If you wish to write a redis client from scratch, you must first invent the universe.
About
Redo is a pipelined redis client written in Erlang. It lacks any sort of syntactic sugar. The only API function is redo:cmd, which takes a raw redis command.
Build
$ make
Test
Unit tests
$ ./rebar eunit suite=redo
Local read benchmark
$ erl -pa ebin
1> bench:sync(1000).
91ms
10989 req/sec
2> bench:async(1000, 100).
38ms
26315 req/sec
Concurrency test
$ erl -pa ebin
1> redo_concurrency_test:run(20, 100). %% 20 pids, 100 random operations performed per pid
Start
No arguments: register process as "redo"
$ erl -pa ebin
1> redo:start_link().
{ok, <0.33.0>
2> whereis(redo).
<0.33.0>
3> redo:cmd(["PING"]).
<<"PONG">>
Register with custom name
erl -pa ebin
1> redo:start_link(myclient).
{ok,<0.33.0>}
2> whereis(myclient).
<0.33.0>
8> redo:cmd(myclient, ["PING"]).
<<"PONG">>
Start anonymous Redo process
erl -pa ebin
1> {ok, Pid} = redo:start_link(undefined).
{ok,<0.33.0>}
2> redo:cmd(Pid, ["PING"]).
<<"PONG">>
Specifying connection options
erl -pa ebin
1> redo:start_link([{host, "localhost"}, {port, 6379}]).
{ok,<0.33.0>}
2> redo:cmd(["PING"]).
<<"PONG">>
3> redo:start_link(myclient, [{host, "localhost"}, {port, 6379}]).
{ok,<0.37.0>}
4> redo:cmd(myclient, ["PING"]).
<<"PONG">>
Commands
erl -pa ebin
1> redo:start_link().
<0.33.0>
2> redo:cmd(["SET", "foo"]).
{error,<<"ERR wrong number of arguments for 'set' command">>}
3> redo:cmd(["SET", "foo", "bar"]).
<<"OK">>
4> redo:cmd(["GET", "foo"]).
<<"bar">>
5> redo:cmd(["HMSET", "hfoo", "ONE", "ABC", "TWO", "DEF"]).
<<"OK">>
6> redo:cmd(["HGETALL", "hfoo"]).
[<<"ONE">>,<<"ABC">>,<<"TWO">>,<<"DEF">>]
Pipelined commands
1> redo:start_link().
<0.33.>
2> redo:cmd([["GET", "foo"], ["HGETALL", "hfoo"]]).
[<<"bar">>, [<<"ONE">>,<<"ABC">>,<<"TWO">>,<<"DEF">>]]
Pub/Sub
$ erl -pa ebin
1> redo:start_link().
{ok,<0.33.0>}
2> Ref = redo:subscribe("chfoo").
#Ref<0.0.0.42>
3> (fun() -> receive {Ref, Res} -> Res after 10000 -> timeout end end)().
[<<"subscribe">>,<<"chfoo">>,1]
4> redo:start_link(client).
{ok,<0.39.0>}
5> redo:cmd(client, ["PUBLISH", "chfoo", "hello"]).
1
6> (fun() -> receive {Ref, Res} -> Res after 10000 -> timeout end end)().
[<<"message">>,<<"chfoo">>,<<"hello">>]
%% restart redis server...
7> (fun() -> receive {Ref, Res} -> Res after 10000 -> timeout end end)().
closed
8> f(Ref).
ok
9> Ref = redo:subscribe("chfoo").
#Ref<0.0.0.68>
10> (fun() -> receive {Ref, Res} -> Res after 10000 -> timeout end end)().
[<<"subscribe">>,<<"chfoo">>,1]
11> redo:cmd(client, ["PUBLISH", "chfoo", "hello again"]).
1
12> (fun() -> receive {Ref, Res} -> Res after 10000 -> timeout end end)().
[<<"message">>,<<"chfoo">>,<<"hello again">>]