Import upstream version 1.2.0+git20190128.1.6845ed5
Debian Janitor
2 years ago
0 | language: erlang | |
1 | sudo: required | |
2 | notifications: | |
3 | email: false | |
4 | otp_release: | |
5 | - 21.0.1 | |
6 | - 20.3 | |
7 | - 19.3 | |
8 | - 19.2 | |
9 | - 19.1 | |
10 | - 19.0 | |
11 | - 18.3 | |
12 | - 18.2.1 | |
13 | - 18.1 | |
14 | - 17.5 | |
15 | - 17.4 | |
16 | - 17.3 | |
17 | - 17.1 | |
18 | - 17.0 | |
19 | - R16B03-1 | |
20 | - R16B03 | |
21 | - R16B02 | |
22 | - R16B01 | |
23 | services: | |
24 | - redis-server |
113 | 113 | where the values are the redis responses in the same order as the |
114 | 114 | commands you provided. |
115 | 115 | |
116 | To start the client, use any of the `eredis:start_link/0,1,2,3,4,5` | |
117 | functions. They all include sensible defaults. `start_link/5` takes | |
116 | To start the client, use any of the `eredis:start_link/0,1,2,3,4,5,6,7` | |
117 | functions. They all include sensible defaults. `start_link/7` takes | |
118 | 118 | the following arguments: |
119 | 119 | |
120 | 120 | * Host, dns name or ip adress as string; or unix domain socket as {local, Path} (available in OTP 19+) |
122 | 122 | * Database, integer or 0 for default database |
123 | 123 | * Password, string or empty string([]) for no password |
124 | 124 | * Reconnect sleep, integer of milliseconds to sleep between reconnect attempts |
125 | * Connect timeout, timeout value in milliseconds to use in `gen_tcp:connect`, default is 5000 | |
126 | * Socket options, proplist of options to be sent to `gen_tcp:connect`, default is `?SOCKET_OPTS` | |
125 | 127 | |
126 | 128 | ## Reconnecting on Redis down / network failure / timeout / etc |
127 | 129 |
32 | 32 | |
33 | 33 | -define(NL, "\r\n"). |
34 | 34 | |
35 | -define(SOCKET_OPTS, [binary, {active, once}, {packet, raw}, {reuseaddr, false}, | |
36 | {send_timeout, ?SEND_TIMEOUT}]). | |
35 | -define(SOCKET_MODE, binary). | |
36 | -define(SOCKET_OPTS, [{active, once}, {packet, raw}, {reuseaddr, false}, | |
37 | {keepalive, false}, {send_timeout, ?SEND_TIMEOUT}]). | |
37 | 38 | |
38 | 39 | -define(RECV_TIMEOUT, 5000). |
39 | 40 | -define(SEND_TIMEOUT, 5000). |
3 | 3 | def project do |
4 | 4 | [ |
5 | 5 | app: :eredis, |
6 | version: "1.1.0", | |
6 | version: "1.2.0", | |
7 | 7 | elixir: "~> 1.5.1", |
8 | 8 | start_permanent: Mix.env == :prod, |
9 | 9 | deps: deps() |
0 | {application, eredis, [ | |
1 | {description, "Erlang Redis Client"}, | |
2 | {vsn, "1.1.0"}, | |
3 | {modules, [eredis, eredis_client, eredis_parser, eredis_sub, eredis_sub_client]}, | |
4 | {registered, []}, | |
5 | {applications, [kernel, stdlib]}, | |
6 | {maintainers, ["Knut Nesheim"]}, | |
7 | {licenses, ["MIT"]} | |
8 | ]}. | |
0 | {application,eredis, | |
1 | [{description,"Erlang Redis Client"}, | |
2 | {vsn,"1.2.0"}, | |
3 | {modules,[eredis,eredis_client,eredis_parser,eredis_sub, | |
4 | eredis_sub_client]}, | |
5 | {registered,[]}, | |
6 | {applications,[kernel,stdlib]}, | |
7 | {maintainers,["Knut Nesheim"]}, | |
8 | {licenses,["MIT"]}]}. |
13 | 13 | -define(TIMEOUT, 5000). |
14 | 14 | |
15 | 15 | -export([start_link/0, start_link/1, start_link/2, start_link/3, start_link/4, |
16 | start_link/5, start_link/6, stop/1, q/2, q/3, qp/2, qp/3, q_noreply/2, | |
16 | start_link/5, start_link/6, start_link/7, stop/1, q/2, q/3, qp/2, qp/3, q_noreply/2, | |
17 | 17 | q_async/2, q_async/3]). |
18 | 18 | |
19 | 19 | %% Exported for testing |
45 | 45 | start_link(Host, Port, Database, Password, ReconnectSleep) -> |
46 | 46 | start_link(Host, Port, Database, Password, ReconnectSleep, ?TIMEOUT). |
47 | 47 | |
48 | start_link(Host, Port, Database, Password, ReconnectSleep, ConnectTimeout) | |
48 | start_link(Host, Port, Database, Password, ReconnectSleep, ConnectTimeout) -> | |
49 | start_link(Host, Port, Database, Password, ReconnectSleep, ConnectTimeout, []). | |
50 | ||
51 | start_link(Host, Port, Database, Password, ReconnectSleep, ConnectTimeout, SocketOptions) | |
49 | 52 | when is_list(Host) orelse |
50 | 53 | (is_tuple(Host) andalso tuple_size(Host) =:= 2 andalso element(1, Host) =:= local), |
51 | 54 | is_integer(Port), |
52 | 55 | is_integer(Database) orelse Database == undefined, |
53 | 56 | is_list(Password), |
54 | 57 | is_integer(ReconnectSleep) orelse ReconnectSleep =:= no_reconnect, |
55 | is_integer(ConnectTimeout) -> | |
58 | is_integer(ConnectTimeout), | |
59 | is_list(SocketOptions) -> | |
56 | 60 | |
57 | 61 | eredis_client:start_link(Host, Port, Database, Password, |
58 | ReconnectSleep, ConnectTimeout). | |
62 | ReconnectSleep, ConnectTimeout, SocketOptions). | |
59 | 63 | |
60 | 64 | %% @doc: Callback for starting from poolboy |
61 | 65 | -spec start_link(server_args()) -> {ok, Pid::pid()} | {error, Reason::term()}. |
66 | 70 | Password = proplists:get_value(password, Args, ""), |
67 | 71 | ReconnectSleep = proplists:get_value(reconnect_sleep, Args, 100), |
68 | 72 | ConnectTimeout = proplists:get_value(connect_timeout, Args, ?TIMEOUT), |
69 | start_link(Host, Port, Database, Password, ReconnectSleep, ConnectTimeout). | |
73 | SocketOptions = proplists:get_value(socket_options, Args, []), | |
74 | ||
75 | start_link(Host, Port, Database, Password, ReconnectSleep, ConnectTimeout, SocketOptions). | |
70 | 76 | |
71 | 77 | stop(Client) -> |
72 | 78 | eredis_client:stop(Client). |
24 | 24 | -include("eredis.hrl"). |
25 | 25 | |
26 | 26 | %% API |
27 | -export([start_link/6, stop/1, select_database/2]). | |
27 | -export([start_link/7, stop/1, select_database/2]). | |
28 | 28 | |
29 | 29 | -export([do_sync_command/2]). |
30 | 30 | |
39 | 39 | database :: binary() | undefined, |
40 | 40 | reconnect_sleep :: reconnect_sleep() | undefined, |
41 | 41 | connect_timeout :: integer() | undefined, |
42 | socket_options :: list(), | |
42 | 43 | |
43 | 44 | socket :: port() | undefined, |
44 | 45 | parser_state :: #pstate{} | undefined, |
54 | 55 | Database::integer() | undefined, |
55 | 56 | Password::string(), |
56 | 57 | ReconnectSleep::reconnect_sleep(), |
57 | ConnectTimeout::integer() | undefined) -> | |
58 | ConnectTimeout::integer() | undefined, | |
59 | SocketOptions::list()) -> | |
58 | 60 | {ok, Pid::pid()} | {error, Reason::term()}. |
59 | start_link(Host, Port, Database, Password, ReconnectSleep, ConnectTimeout) -> | |
61 | start_link(Host, Port, Database, Password, ReconnectSleep, ConnectTimeout, SocketOptions) -> | |
60 | 62 | gen_server:start_link(?MODULE, [Host, Port, Database, Password, |
61 | ReconnectSleep, ConnectTimeout], []). | |
63 | ReconnectSleep, ConnectTimeout, SocketOptions], []). | |
62 | 64 | |
63 | 65 | |
64 | 66 | stop(Pid) -> |
68 | 70 | %% gen_server callbacks |
69 | 71 | %%==================================================================== |
70 | 72 | |
71 | init([Host, Port, Database, Password, ReconnectSleep, ConnectTimeout]) -> | |
73 | init([Host, Port, Database, Password, ReconnectSleep, ConnectTimeout, SocketOptions]) -> | |
72 | 74 | State = #state{host = Host, |
73 | 75 | port = Port, |
74 | 76 | database = read_database(Database), |
75 | 77 | password = list_to_binary(Password), |
76 | 78 | reconnect_sleep = ReconnectSleep, |
77 | 79 | connect_timeout = ConnectTimeout, |
80 | socket_options = SocketOptions, | |
78 | 81 | |
79 | 82 | parser_state = eredis_parser:init(), |
80 | 83 | queue = queue:new()}, |
305 | 308 | local -> 0; |
306 | 309 | _ -> State#state.port |
307 | 310 | end, |
308 | case gen_tcp:connect(Addr, Port, | |
309 | [AFamily | ?SOCKET_OPTS], State#state.connect_timeout) of | |
311 | ||
312 | SocketOptions = lists:ukeymerge(1, lists:keysort(1, State#state.socket_options), lists:keysort(1, ?SOCKET_OPTS)), | |
313 | ConnectOptions = [AFamily | [?SOCKET_MODE | SocketOptions]], | |
314 | ||
315 | case gen_tcp:connect(Addr, Port, ConnectOptions, State#state.connect_timeout) of | |
310 | 316 | {ok, Socket} -> |
311 | 317 | case authenticate(Socket, State#state.password) of |
312 | 318 | ok -> |
309 | 309 | %% synchronous and if Redis returns something we don't expect, we |
310 | 310 | %% crash. Returns {ok, State} or {error, Reason}. |
311 | 311 | connect(State) -> |
312 | case gen_tcp:connect(State#state.host, State#state.port, ?SOCKET_OPTS) of | |
312 | case gen_tcp:connect(State#state.host, State#state.port, [?SOCKET_MODE | ?SOCKET_OPTS]) of | |
313 | 313 | {ok, Socket} -> |
314 | 314 | case authenticate(Socket, State#state.password) of |
315 | 315 | ok -> |
27 | 27 | eredis_sub:ack_message(Sub) |
28 | 28 | end |
29 | 29 | end, Channels). |
30 | ||
31 | ||
32 | ||
33 | ||
34 | ||
35 | 30 | |
36 | 31 | pubsub_test() -> |
37 | 32 | Pub = c(), |
7 | 7 | connect_test() -> |
8 | 8 | ?assertMatch({ok, _}, eredis:start_link("127.0.0.1", 6379)), |
9 | 9 | ?assertMatch({ok, _}, eredis:start_link("localhost", 6379)). |
10 | ||
11 | connect_socket_options_test() -> | |
12 | ?assertMatch({ok, _}, eredis:start_link([{socket_options, [{keepalive, true}]}])), | |
13 | ?assertMatch({ok, _}, eredis:start_link("localhost", 6379, 0, "",100, 5000, [{keepalive, true}])). | |
10 | 14 | |
11 | 15 | get_set_test() -> |
12 | 16 | C = c(), |
155 | 159 | process_flag(trap_exit, true), |
156 | 160 | Res = eredis:start_link("localhost", 6378, 0, "", no_reconnect), |
157 | 161 | ?assertMatch({error, _}, Res), |
158 | IsDied = receive {'EXIT', _, _} -> died | |
162 | IsDead = receive {'EXIT', _, _} -> died | |
159 | 163 | after 1000 -> still_alive end, |
160 | 164 | process_flag(trap_exit, false), |
161 | ?assertEqual(died, IsDied). | |
165 | ?assertEqual(died, IsDead). | |
162 | 166 | |
163 | 167 | connection_failure_during_start_reconnect_test() -> |
164 | 168 | process_flag(trap_exit, true), |
165 | 169 | Res = eredis:start_link("localhost", 6378, 0, "", 100), |
166 | 170 | ?assertMatch({ok, _}, Res), |
167 | 171 | {ok, ClientPid} = Res, |
168 | IsDied = receive {'EXIT', ClientPid, _} -> died | |
172 | IsDead = receive {'EXIT', ClientPid, _} -> died | |
169 | 173 | after 400 -> still_alive end, |
170 | 174 | process_flag(trap_exit, false), |
171 | ?assertEqual(still_alive, IsDied). | |
175 | ?assertEqual(still_alive, IsDead). | |
172 | 176 | |
173 | 177 | tcp_closed_test() -> |
174 | 178 | C = c(), |