diff --git a/src/hz.erl b/src/hz.erl index e09ad7b..787875e 100644 --- a/src/hz.erl +++ b/src/hz.erl @@ -582,7 +582,7 @@ next_nonce(AccountID) -> % {ok, #{"reason" := Reason}} -> {error, Reason}; % Error -> Error % end. - case request(["/v3/accounts/", AccountID]) of + case request_sticky(["/v3/accounts/", AccountID]) of {ok, #{"nonce" := Nonce}} -> {ok, Nonce + 1}; {ok, #{"reason" := "Account not found"}} -> {ok, 1}; {ok, #{"reason" := Reason}} -> {error, Reason}; @@ -729,7 +729,7 @@ tx_info(ID) -> post_tx(Data) when is_binary(Data) -> JSON = zj:binary_encode(#{tx => Data}), - request("/v3/transactions", JSON); + request_sticky("/v3/transactions", JSON); post_tx(Data) when is_list(Data) -> post_tx(list_to_binary(Data)). @@ -841,6 +841,14 @@ status_chainends() -> request("/v3/status/chain-ends"). +request_sticky(Path) -> + hz_man:request_sticky(unicode:characters_to_list(Path)). + + +request_sticky(Path, Payload) -> + hz_man:request_sticky(unicode:characters_to_list(Path), Payload). + + request(Path) -> hz_man:request(unicode:characters_to_list(Path)). diff --git a/src/hz_man.erl b/src/hz_man.erl index 4e0207f..17ad352 100644 --- a/src/hz_man.erl +++ b/src/hz_man.erl @@ -21,7 +21,7 @@ timeout/0, timeout/1]). %% The whole point of this module: --export([request/1, request/2]). +-export([request_sticky/1, request_sticky/2,request/1, request/2]). %% gen_server goo -export([start_link/0]). @@ -94,6 +94,25 @@ timeout(Value) when 0 < Value, Value =< 120000 -> gen_server:cast(?MODULE, {timeout, Value}). +-spec request_sticky(Path) -> {ok, Value} | {error, Reason} + when Path :: unicode:charlist(), + Value :: map(), + Reason :: hz:chain_error(). + +request_sticky(Path) -> + gen_server:call(?MODULE, {request_sticky, {get, Path}}, infinity). + + +-spec request_sticky(Path, Data) -> {ok, Value} | {error, Reason} + when Path :: unicode:charlist(), + Data :: unicode:charlist(), + Value :: map(), + Reason :: hz:chain_error(). + +request_sticky(Path, Data) -> + gen_server:call(?MODULE, {request_sticky, {post, Path, Data}}, infinity). + + -spec request(Path) -> {ok, Value} | {error, Reason} when Path :: unicode:charlist(), Value :: map(), @@ -145,6 +164,9 @@ init(none) -> handle_call({request, Request}, From, State) -> NewState = do_request(Request, From, State), {noreply, NewState}; +handle_call({request_sticky, Request}, From, State) -> + NewState = do_request_sticky(Request, From, State), + {noreply, NewState}; handle_call(tls, _, State = #s{tls = TLS}) -> {reply, TLS, State}; handle_call(chain_nodes, _, State = #s{chain_nodes = {Wait, Used}}) -> @@ -160,10 +182,9 @@ handle_call(Unexpected, From, State) -> handle_cast({tls, Boolean}, State) -> NewState = do_tls(Boolean, State), {noreply, NewState}; -handle_cast({chain_nodes, []}, State) -> - {noreply, State#s{chain_nodes = {[], []}}}; -handle_cast({chain_nodes, ToUse}, State) -> - {noreply, State#s{chain_nodes = {ToUse, []}}}; +handle_cast({chain_nodes, List}, State) -> + NewState = do_chain_nodes(List, State), + {noreply, NewState}; handle_cast({timeout, Value}, State) -> {noreply, State#s{timeout = Value}}; handle_cast(Unexpected, State) -> @@ -218,6 +239,14 @@ terminate(_, _) -> %%% Doer Functions +do_chain_nodes([], State) -> + State#s{sticky = none, chain_nodes = {[], []}}; +do_chain_nodes(List = [Sticky], State) -> + State#s{sticky = Sticky, chain_nodes = {List, []}}; +do_chain_nodes([Sticky | List], State) -> + State#s{sticky = Sticky, chain_nodes = {List, []}}. + + do_tls(true, State) -> ok = ssl:start(), State#s{tls = true}; @@ -227,17 +256,21 @@ do_tls(_, State) -> State. -do_request(_, From, State = #s{chain_nodes = {[], []}}) -> +do_request_sticky(_, From, State = #s{sticky = none}) -> ok = gen_server:reply(From, {error, no_nodes}), State; -do_request(Request, - From, - State = #s{tls = false, - fetchers = Fetchers, - chain_nodes = {[Node | Rest], Used}, - timeout = Timeout}) -> +do_request_sticky(Request, + From, + State = #s{tls = TLS, + fetchers = Fetchers, + sticky = Node, + timeout = Timeout}) -> Now = erlang:system_time(nanosecond), - Fetcher = fun() -> hz_fetcher:connect(Node, Request, From, Timeout) end, + Fetcher = + case TLS of + true -> fun() -> hz_fetcher:slowly_connect(Node, Request, From, Timeout) end; + false -> fun() -> hz_fetcher:connect(Node, Request, From, Timeout) end + end, {PID, Mon} = spawn_monitor(Fetcher), New = #fetcher{pid = PID, mon = Mon, @@ -245,15 +278,24 @@ do_request(Request, node = Node, from = From, req = Request}, - State#s{fetchers = [New | Fetchers], chain_nodes = {Rest, [Node | Used]}}; + State#s{fetchers = [New | Fetchers]}. + + +do_request(_, From, State = #s{chain_nodes = {[], []}}) -> + ok = gen_server:reply(From, {error, no_nodes}), + State; do_request(Request, From, - State = #s{tls = true, + State = #s{tls = TLS, fetchers = Fetchers, chain_nodes = {[Node | Rest], Used}, timeout = Timeout}) -> Now = erlang:system_time(nanosecond), - Fetcher = fun() -> hz_fetcher:slowly_connect(Node, Request, From, Timeout) end, + Fetcher = + case TLS of + true -> fun() -> hz_fetcher:slowly_connect(Node, Request, From, Timeout) end; + false -> fun() -> hz_fetcher:connect(Node, Request, From, Timeout) end + end, {PID, Mon} = spawn_monitor(Fetcher), New = #fetcher{pid = PID, mon = Mon,