From a9087a5c9bd63c1f59de1541f98db4b6d951ff16 Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Tue, 7 Apr 2020 18:34:34 +0800 Subject: [PATCH 1/3] improve eetcd:info/0 doc --- README.md | 14 +++++++++++++- src/eetcd.erl | 6 +++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ff12f5b..22acedc 100644 --- a/README.md +++ b/README.md @@ -255,7 +255,19 @@ update_services(#{events := Events}) -> ``` ##### Election Example -![Election Example](https://github.com/zhongwencool/eetcd/blob/master/test/eetcd_election_leader_example.erl) +[Election Example](https://github.com/zhongwencool/eetcd/blob/master/test/eetcd_election_leader_example.erl) + +##### Debug information +```erlang +1>eetcd:info(). +| Name | Status | IP:Port | Conn | Gun |LeaseNum| +| test | Active |127.0.0.1:2379|<0.535.0> |<0.536.0> | 1 | +| test | Active |127.0.0.1:2579|<0.535.0> |<0.539.0> | 2 | +| Name | Status | IP:Port | Conn | ReconnectSecond | +| test | Freeze |127.0.0.1:2479|<0.535.0> | 1.6 | +``` +- `Active` is normal connection. +- `Freeze` is a broken connection who try to reconnect after `ReconnectSecond`. Test ----- diff --git a/src/eetcd.erl b/src/eetcd.erl index 41f1e00..d677bbc 100644 --- a/src/eetcd.erl +++ b/src/eetcd.erl @@ -30,13 +30,17 @@ open(Name, Hosts, Transport, TransportOpts) -> %% The balancing policy is round robin. %% For instance, in 5-node cluster, `connect_all' would require 5 TCP connections, %% This may consume more resources but provide more flexible load balance with better failover performance. +%% `eetcd_conn' will do his best to keep all connections normal, and try to reconnect when connection is broken. +%% The reconnect millisecond is 200 400 800 1600 3200 6400 12800 25600, and keep recycling this reconnection time until normal. %% %% `{mode, random}' creates only one connection to a random endpoint, %% it would pick one address and use it to send all client requests. %% The pinned address is maintained until the client connection is closed. -%% When the client receives an error, it randomly picks another. +%% When the client receives an error, it randomly picks another normal endpoint. %% %% `[{name, string()},{password, string()}]' generates an authentication token based on a given user name and password. +%% +%% You can use `eetcd:info/0' to see the internal connection status. -spec open(name(), [string()], [{mode, connect_all|random} |{name, string()} | {password, string()}], From 8525c6ff37260857806270ac078bd3240bfd819d Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Tue, 7 Apr 2020 19:04:56 +0800 Subject: [PATCH 2/3] eetcd:lock/3 support name and add document for lock --- src/eetcd.erl | 2 +- src/eetcd_auth.erl | 2 +- src/eetcd_cluster.erl | 2 +- src/eetcd_election.erl | 2 +- src/eetcd_kv.erl | 2 +- src/eetcd_lease.erl | 2 +- src/eetcd_lock.erl | 33 ++++++++++++++++++++++++--------- 7 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/eetcd.erl b/src/eetcd.erl index d677bbc..fa39314 100644 --- a/src/eetcd.erl +++ b/src/eetcd.erl @@ -88,7 +88,7 @@ new(Context) when is_map(Context) -> Context. %% @doc Timeout is an integer greater than zero which specifies how many milliseconds to wait for a reply, %% or the atom infinity to wait indefinitely. %% If no reply is received within the specified time, the function call fails with `{error, timeout}'. --spec with_timeout(context(), pos_integer()) -> context(). +-spec with_timeout(context(), pos_integer()|infinity) -> context(). with_timeout(Context, Timeout) when is_integer(Timeout); Timeout == infinity -> case Timeout < 100 of true -> diff --git a/src/eetcd_auth.erl b/src/eetcd_auth.erl index 3537f01..c276e80 100644 --- a/src/eetcd_auth.erl +++ b/src/eetcd_auth.erl @@ -357,5 +357,5 @@ new(Context) -> eetcd:new(Context). %% @doc Timeout is an integer greater than zero which specifies how many milliseconds to wait for a reply, %% or the atom infinity to wait indefinitely. Default value is 5000. %% If no reply is received within the specified time, the function call fails with `{error, timeout}'. --spec with_timeout(context(), pos_integer()) -> context(). +-spec with_timeout(context(), pos_integer()|infinity) -> context(). with_timeout(Context, Timeout) -> eetcd:with_timeout(Context, Timeout). diff --git a/src/eetcd_cluster.erl b/src/eetcd_cluster.erl index 5792fec..c0dcdb8 100644 --- a/src/eetcd_cluster.erl +++ b/src/eetcd_cluster.erl @@ -147,5 +147,5 @@ new(Context) -> eetcd:new(Context). %% @doc Timeout is an integer greater than zero which specifies how many milliseconds to wait for a reply, %% or the atom infinity to wait indefinitely. Default value is 5000. %% If no reply is received within the specified time, the function call fails with `{error, timeout}'. --spec with_timeout(context(), pos_integer()) -> context(). +-spec with_timeout(context(), pos_integer()|infinity) -> context(). with_timeout(Context, Timeout) -> eetcd:with_timeout(Context, Timeout). diff --git a/src/eetcd_election.erl b/src/eetcd_election.erl index 8bc1b4d..b980e56 100644 --- a/src/eetcd_election.erl +++ b/src/eetcd_election.erl @@ -18,7 +18,7 @@ new(Ctx) -> eetcd:new(Ctx). %% @doc Timeout is an integer greater than zero which specifies how many milliseconds to wait for a reply, %% or the atom infinity to wait indefinitely. Default value is 5000. %% If no reply is received within the specified time, the function call fails with `{error, timeout}'. --spec with_timeout(context(), pos_integer()) -> context(). +-spec with_timeout(context(), pos_integer()|infinity) -> context(). with_timeout(Ctx, Timeout) -> eetcd:with_timeout(Ctx, Timeout). %%% @doc name is the election's identifier for the campaign. diff --git a/src/eetcd_kv.erl b/src/eetcd_kv.erl index 14aa0a6..57d3a2c 100644 --- a/src/eetcd_kv.erl +++ b/src/eetcd_kv.erl @@ -29,7 +29,7 @@ new() -> #{}. %% @doc Timeout is an integer greater than zero which specifies how many milliseconds to wait for a reply, %% or the atom infinity to wait indefinitely. Default value is 5000. %% If no reply is received within the specified time, the function call fails with `{error, timeout}'. --spec with_timeout(context(), pos_integer()) -> context(). +-spec with_timeout(context(), pos_integer()|infinity) -> context(). with_timeout(Context, Timeout) -> eetcd:with_timeout(Context, Timeout). %%% @doc Sets data for the request's `key'. diff --git a/src/eetcd_lease.erl b/src/eetcd_lease.erl index 8c31f5e..d7646c3 100644 --- a/src/eetcd_lease.erl +++ b/src/eetcd_lease.erl @@ -22,7 +22,7 @@ new(Context) -> eetcd:new(Context). %% @doc Timeout is an integer greater than zero which specifies how many milliseconds to wait for a reply, %% or the atom infinity to wait indefinitely. Default value is 5000. %% If no reply is received within the specified time, the function call fails with `{error, timeout}'. --spec with_timeout(context(), pos_integer()) -> context(). +-spec with_timeout(context(), pos_integer()|infinity) -> context(). with_timeout(Context, Timeout) -> eetcd:with_timeout(Context, Timeout). %% @doc Grant creates a new lease with the provided TTL in seconds. diff --git a/src/eetcd_lock.erl b/src/eetcd_lock.erl index 85decf2..75b73e4 100644 --- a/src/eetcd_lock.erl +++ b/src/eetcd_lock.erl @@ -10,36 +10,51 @@ new(Context) -> eetcd:new(Context). %% @doc Timeout is an integer greater than zero which specifies how many milliseconds to wait for a reply, -%% or the atom infinity to wait indefinitely. Default value is 5000. +%% or the atom infinity to wait indefinitely. %% If no reply is received within the specified time, the function call fails with `{error, timeout}'. --spec with_timeout(context(), pos_integer()) -> context(). +-spec with_timeout(context(), pos_integer()|infinity) -> context(). with_timeout(Context, Timeout) -> eetcd:with_timeout(Context, Timeout). +%%% @doc name is the identifier for the distributed shared lock to be acquired. -spec with_name(context(), Name :: binary()) -> context(). with_name(Context, Name) -> maps:put(name, Name, Context). +%%% @doc lease is the ID of the lease that will be attached to ownership of the +%%% lock. If the lease expires or is revoked and currently holds the lock, +%%% the lock is automatically released. Calls to Lock with the same lease will +%%% be treated as a single acquisition; locking twice with the same lease is a no-op. -spec with_lease_id(context(), LeaseID :: pos_integer()) -> context(). with_lease_id(Context, LeaseID) -> maps:put(lease, LeaseID, Context). +%%% @doc key is a key that will exist on etcd for the duration that the Lock caller +%% owns the lock. Users should not modify this key or the lock may exhibit undefined behavior. -spec with_key(context(), Key :: binary()) -> context(). with_key(Context, Key) -> maps:put(key, Key, Context). - - +%%% @doc Lock acquires a distributed shared lock on a given named lock. +%%% On success, it will return a unique key that exists so long as the +%%% lock is held by the caller. This key can be used in conjunction with +%%% transactions to safely ensure updates to etcd only occur while holding +%%% lock ownership. The lock is held until Unlock is called on the key or the +%%% lease associate with the owner expires. -spec lock(Ctx :: context()) -> {ok, router_pb:'Etcd.LockResponse'()} | {error, eetcd_error()}. lock(Context) -> eetcd_lock_gen:lock(Context). --spec lock(Ctx :: context(), Name :: binary(), LeaseID :: pos_integer()) -> {ok, router_pb:'Etcd.LockResponse'()} | {error, eetcd_error()}. +-spec lock(Ctx :: context()|name(), Name :: binary(), LeaseID :: pos_integer()) -> {ok, router_pb:'Etcd.LockResponse'()} | {error, eetcd_error()}. lock(Context0, Name, LeaseID) -> - Context = with_lease_id(with_name(Context0, Name), LeaseID), + Context1 = new(Context0), + Context = with_lease_id(with_name(Context1, Name), LeaseID), eetcd_lock_gen:lock(Context). - --spec unlock(Ctx :: context(), Key :: binary()) -> {ok, router_pb:'Etcd.UnlockRequest'()} | {error, eetcd_error()}. +%%% @doc Unlock takes a key returned by Lock and releases the hold on lock. The +%%% next Lock caller waiting for the lock will then be woken up and given +%%% ownership of the lock. +-spec unlock(Ctx :: context()|name(), Key :: binary()) -> {ok, router_pb:'Etcd.UnlockRequest'()} | {error, eetcd_error()}. unlock(Context0, Key) -> - Context = with_key(Context0, Key), + Context1 = new(Context0), + Context = with_key(Context1, Key), eetcd_lock_gen:unlock(Context). From 4d1558d2e166ac35787a47b03bc0aad02423d450 Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Tue, 7 Apr 2020 19:06:59 +0800 Subject: [PATCH 3/3] rename eetcd_lock:with_lease_id/2 to with_lease/2 --- src/eetcd_lock.erl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/eetcd_lock.erl b/src/eetcd_lock.erl index 75b73e4..1858cee 100644 --- a/src/eetcd_lock.erl +++ b/src/eetcd_lock.erl @@ -1,7 +1,7 @@ -module(eetcd_lock). -include("eetcd.hrl"). --export([new/1, with_timeout/2, with_name/2, with_lease_id/2, with_key/2]). +-export([new/1, with_timeout/2, with_name/2, with_lease/2, with_key/2]). -export([lock/1, lock/3, unlock/2]). @@ -24,8 +24,8 @@ with_name(Context, Name) -> %%% lock. If the lease expires or is revoked and currently holds the lock, %%% the lock is automatically released. Calls to Lock with the same lease will %%% be treated as a single acquisition; locking twice with the same lease is a no-op. --spec with_lease_id(context(), LeaseID :: pos_integer()) -> context(). -with_lease_id(Context, LeaseID) -> +-spec with_lease(context(), LeaseID :: pos_integer()) -> context(). +with_lease(Context, LeaseID) -> maps:put(lease, LeaseID, Context). %%% @doc key is a key that will exist on etcd for the duration that the Lock caller @@ -47,7 +47,7 @@ lock(Context) -> -spec lock(Ctx :: context()|name(), Name :: binary(), LeaseID :: pos_integer()) -> {ok, router_pb:'Etcd.LockResponse'()} | {error, eetcd_error()}. lock(Context0, Name, LeaseID) -> Context1 = new(Context0), - Context = with_lease_id(with_name(Context1, Name), LeaseID), + Context = with_lease(with_name(Context1, Name), LeaseID), eetcd_lock_gen:lock(Context). %%% @doc Unlock takes a key returned by Lock and releases the hold on lock. The