Fix flowed child_spec abstraction (#48)

* MG-64: Add find_pool function

* MG-64: Refactor options

* MG-64: Fix linter and dialyzer errors

* MG-64: Fix tests

* MG-64: Add review fixes

Remove unnecessary functionality
Rename pool_name -> name option
Define child_spec as woody_client_behaviour

* MG-64: Add review fixes 2
This commit is contained in:
Dmitry Manik 2017-03-03 17:34:41 +03:00 committed by GitHub
parent 66884b7020
commit 7650c1f9f1
6 changed files with 46 additions and 64 deletions

View File

@ -55,19 +55,16 @@ Erlang реализация [Библиотеки RPC вызовов для об
`woody_context:new/0` - можно использовать для создания контекста корневого запроса с автоматически сгенерированным уникальным RPC ID.
Можно создать пул соединений для thrift клиента (например, для установления _keep alive_ соединений с сервером): `woody_client_thrift:start_pool/2` и затем использовать его при работе с `woody_client`. NB: второй параметр - Options из `hackney:start_pool/2`, например `{timeout, 150000}, {max_connections, 100}`:
Можно создать пул соединений для thrift клиента (например, для установления _keep alive_ соединений с сервером). Для этого надо использовать
`woody_client:connection_pool_spec/2`. Для работы с определенным пулом в Options есть поле `transport_opts => [{pool, pool_name}, {timeout, 150000}, {max_connections, 100}]`.
```erlang
15> Pool = my_client_pool.
16> ok = woody_client_thrift:start_pool(Pool, 10).
15> Opts = Opts#{transport_opts => [{pool, my_client_pool}]}.
16> supervisor:start_child(Sup, woody_client:connection_pool_spec(Opts)).
17> Context2 = woody_context:new(<<"myUniqRequestID2">>).
18> {ok, Result2} = woody_client:call(Request, Opts, Context2).
```
Есть возможность стартовать пул в ручную. Для этого надо использовать `woody_client_thrift:child_spec/2`.
Закрыть пул можно с помошью `woody_client_thrift:stop_pool/1`.
`Context` также позволяет аннотировать RPC запросы дополнительными мета данными в виде _key-value_. `Context` передается только в запросах и его расширение возможно только в режиме _append-only_ (т.е. на попытку переопределить уже существующую запись в `context meta`, библиотека вернет ошибку). Поскольку на транспортном уровне контекст передается в виде custom HTTP заголовков, синтаксис _key-value_ должен следовать ограничениям [RFC7230 ](https://tools.ietf.org/html/rfc7230#section-3.2.6). Размер ключа записи метаданных не должен превышать _53 байта_ (см. остальные требования к метаданным в [описании библиотеки](http://coredocs.rbkmoney.com/design/ms/platform/rpc-lib/#rpc_2)).
```erlang

View File

@ -6,7 +6,9 @@
-include("woody_defs.hrl").
%% API
-export([call/2, call/3]).
-export([connection_pool_spec/1]).
-export([call /2]).
-export([call /3]).
%% Types
-type options() :: #{
@ -28,6 +30,11 @@
%%
%% API
%%
-spec connection_pool_spec(options()) ->
supervisor:child_spec().
connection_pool_spec(Options) ->
woody_client_behaviour:connection_pool_spec(Options).
-spec call(woody:request(), options()) ->
{ok, woody:result()} |
{exception, woody_error:business_error()} |

View File

@ -1,9 +1,17 @@
-module(woody_client_behaviour).
-export([call/3]).
-export([connection_pool_spec/1]).
-export([call /3]).
%% Behaviour definition
-callback call(woody:request(), woody_client:options(), woody_context:ctx()) -> woody_client:result().
-callback connection_pool_spec(woody_client:options()) -> supervisor:child_spec().
-spec connection_pool_spec(woody_client:options()) ->
supervisor:child_spec().
connection_pool_spec(Options) ->
Handler = woody_util:get_protocol_handler(client, Options),
Handler:connection_pool_spec(Options).
-spec call(woody:request(), woody_client:options(), woody_context:ctx()) ->
woody_client:result().

View File

@ -5,13 +5,9 @@
-include_lib("thrift/include/thrift_constants.hrl").
-include("woody_defs.hrl").
%% API
-export([child_spec/2]).
-export([start_pool/2]).
-export([stop_pool /1]).
%% woody_client_behaviour callback
-export([call/3]).
-export([call /3]).
-export([connection_pool_spec/1]).
%% Types
-type thrift_client() :: term().
@ -22,20 +18,10 @@
%%
%% API
%%
-spec child_spec(any(), list(tuple())) ->
-spec connection_pool_spec(woody_client:options()) ->
supervisor:child_spec().
child_spec(Name, Options) ->
woody_client_thrift_http_transport:child_spec(Name, Options).
-spec start_pool(any(), list(tuple())) ->
ok.
start_pool(Name, Options) ->
woody_client_thrift_http_transport:start_client_pool(Name, Options).
-spec stop_pool(any()) ->
ok | {error, not_found | simple_one_for_one}.
stop_pool(Name) ->
woody_client_thrift_http_transport:stop_client_pool(Name).
connection_pool_spec(Options) ->
woody_client_thrift_http_transport:connection_pool_spec(get_transport_opts(Options)).
-spec call(woody:request(), woody_client:options(), woody_context:ctx()) ->
woody_client:result().

View File

@ -6,10 +6,8 @@
-include("woody_defs.hrl").
%% API
-export([new /3]).
-export([start_client_pool/2]).
-export([stop_client_pool /1]).
-export([child_spec /2]).
-export([new /3]).
-export([connection_pool_spec/1]).
%% Thrift transport callbacks
-export([read/2, write/2, flush/1, close/1]).
@ -49,21 +47,12 @@ new(Url, Opts, Context) ->
}),
Transport.
-spec child_spec(any(), options()) ->
-spec connection_pool_spec(options()) ->
supervisor:child_spec().
child_spec(Name, Options) ->
connection_pool_spec(Options) ->
Name = proplists:get_value(pool, Options),
hackney_pool:child_spec(Name, Options).
-spec start_client_pool(any(), options()) ->
ok.
start_client_pool(Name, Options) ->
hackney_pool:start_pool(Name, Options).
-spec stop_client_pool(any()) ->
ok | {error, not_found | simple_one_for_one}.
stop_client_pool(Name) ->
hackney_pool:stop_pool(Name).
%%
%% Thrift transport callbacks
%%

View File

@ -51,7 +51,6 @@
call_no_headers_503_test/1,
call_no_headers_504_test/1,
call3_ok_default_ev_handler_test/1,
call_with_client_pool_test/1,
call_thrift_multiplexed_test/1,
server_http_req_validation_test/1,
try_bad_handler_spec_test/1,
@ -167,7 +166,6 @@ all() ->
call_no_headers_503_test,
call_no_headers_504_test,
call3_ok_default_ev_handler_test,
call_with_client_pool_test,
call_thrift_multiplexed_test,
server_http_req_validation_test,
try_bad_handler_spec_test,
@ -215,8 +213,8 @@ init_per_testcase(TC, C) when
[{sup, Sup} | C];
init_per_testcase(find_multiple_pools_test, C) ->
{ok, Sup} = start_tc_sup(),
Pool1 = {swords , {15000, 100}},
Pool2 = {shields, {undefined, 50}},
Pool1 = {swords, 15000, 100},
Pool2 = {shields, undefined, 50},
ok = start_woody_server_with_pools(woody_ct, Sup, ['Weapons', 'Powerups'], [Pool1, Pool2]),
[{sup, Sup} | C];
init_per_testcase(_, C) ->
@ -254,12 +252,21 @@ start_woody_server_with_pools(Id, Sup, Services, Params) ->
}),
{ok, WoodyServer} = supervisor:start_child(Sup, Server),
Specs = [woody_client_thrift:child_spec(Pool, pool_options(Options)) || {Pool, Options} <- Params],
_ = [supervisor:start_child(WoodyServer, Spec) || Spec <- Specs],
Specs = [woody_client:connection_pool_spec(pool_opts(Pool)) || Pool <- Params],
_ = [supervisor:start_child(WoodyServer, Spec) || Spec <- Specs],
ok.
pool_options({Timeout, MaxConnections}) ->
[{timeout, Timeout}, {max_connections, MaxConnections}].
pool_opts(Pool) ->
{Url, _} = get_service_endpoint('Weapons'),
#{
url => Url,
event_handler => ?MODULE,
transport_opts => start_pool_opts(Pool)
}.
start_pool_opts({Name, Timeout, MaxConnections}) ->
[{pool, Name}, {timeout, Timeout}, {max_connections, MaxConnections}].
get_handler('Powerups') ->
{
@ -495,18 +502,6 @@ call_fail_w_no_headers(Id, Class, Details) ->
ok
end.
call_with_client_pool_test(_) ->
Pool = guns,
ok = woody_client_thrift:start_pool(Pool, [{max_connections, 10}]),
Gun = <<"Enforcer">>,
Context = make_context(<<"call_with_client_pool">>),
{Url, Service} = get_service_endpoint('Weapons'),
Expect = {ok, genlib_map:get(Gun, ?WEAPONS)},
Expect = woody_client:call({Service, get_weapon, [Gun, self_to_bin()]},
#{url => Url, event_handler => ?MODULE, pool => Pool}, Context),
{ok, _} = receive_msg(Gun, Context),
ok = woody_client_thrift:stop_pool(Pool).
find_multiple_pools_test(_) ->
true = is_pid(hackney_pool:find_pool(swords)),
true = is_pid(hackney_pool:find_pool(shields)).