mirror of
https://github.com/valitydev/bender.git
synced 2024-11-06 00:55:20 +00:00
MSPF-567: Generate ID's without ExternalID (#30)
* Handle generator service requests
* Upgrade bender_proto
* Add tests and test client
* Add new path to sample config
* Remove debug log & retry_strategy
* Remove irrelevant tests from groups, shorten test config
* Configure thrift services individually
* Refactor sequence generation test
* Upgrade genlib to a version with fixed possible race condition in pmap
* Add forgotten coma
* Pad mapping because I need a signed commit to be able to merge 😠
This commit is contained in:
parent
90ca71b80a
commit
b392d60018
@ -63,7 +63,7 @@ init([]) ->
|
||||
transport_opts => get_transport_opts(),
|
||||
shutdown_timeout => get_shutdown_timeout(),
|
||||
event_handler => EventHandlers,
|
||||
handlers => [get_handler_spec()],
|
||||
handlers => get_handler_spec(),
|
||||
additional_routes => get_routes(EventHandlers)
|
||||
}
|
||||
),
|
||||
@ -104,15 +104,24 @@ get_shutdown_timeout() ->
|
||||
genlib_app:env(?MODULE, shutdown_timeout, 0).
|
||||
|
||||
-spec get_handler_spec() ->
|
||||
woody:http_handler(woody:th_handler()).
|
||||
[woody:http_handler(woody:th_handler())].
|
||||
|
||||
get_handler_spec() ->
|
||||
Opts = genlib_app:env(?MODULE, service, #{}),
|
||||
Path = maps:get(path, Opts, <<"/v1/bender">>),
|
||||
{Path, {
|
||||
{bender_thrift, 'Bender'},
|
||||
bender_handler
|
||||
}}.
|
||||
Opts = genlib_app:env(?MODULE, services, #{}),
|
||||
Bender = maps:get(bender, Opts, #{}),
|
||||
Generator = maps:get(generator, Opts, #{}),
|
||||
BenderPath = maps:get(path, Bender, <<"/v1/bender">>),
|
||||
GeneratorPath = maps:get(generator_path, Generator, <<"/v1/generator">>),
|
||||
[
|
||||
{BenderPath, {
|
||||
{bender_thrift, 'Bender'},
|
||||
bender_handler
|
||||
}},
|
||||
{GeneratorPath, {
|
||||
{bender_thrift, 'Generator'},
|
||||
generator_handler
|
||||
}}
|
||||
].
|
||||
|
||||
-spec get_routes(woody:ev_handlers()) ->
|
||||
[woody_server_thrift_http_handler:route(_)].
|
||||
|
@ -3,6 +3,7 @@
|
||||
%% API
|
||||
|
||||
-export([bind/4]).
|
||||
-export([generate/2]).
|
||||
-export([get_internal_id/2]).
|
||||
|
||||
%% Machinery callbacks
|
||||
|
66
apps/bender/src/generator_handler.erl
Normal file
66
apps/bender/src/generator_handler.erl
Normal file
@ -0,0 +1,66 @@
|
||||
-module(generator_handler).
|
||||
|
||||
%% Woody handler
|
||||
|
||||
-behaviour(woody_server_thrift_handler).
|
||||
|
||||
-export([handle_function/4]).
|
||||
|
||||
-include_lib("bender_proto/include/bender_thrift.hrl").
|
||||
|
||||
-include("bender_internal.hrl").
|
||||
|
||||
-type woody_context() :: woody_context:ctx().
|
||||
|
||||
-type schema() :: bender:schema().
|
||||
-type generate_id_result() :: bender_thrift:'GeneratedID'().
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), woody_context(), woody:options()) ->
|
||||
{ok, woody:result()}.
|
||||
|
||||
handle_function(Func, Args, WoodyCtx, Opts) ->
|
||||
scoper:scope(bender,
|
||||
fun() -> handle_function_(Func, Args, WoodyCtx, Opts) end
|
||||
).
|
||||
|
||||
-spec handle_function_(woody:func(), woody:args(), woody_context(), woody:options()) ->
|
||||
{ok, woody:result()}.
|
||||
|
||||
handle_function_('GenerateID', [Schema], WoodyCtx, _Opts) ->
|
||||
generate_id(Schema, WoodyCtx).
|
||||
|
||||
-spec generate_id(bender_thrift:'GenerationSchema'(), woody_context()) ->
|
||||
{ok, generate_id_result()} | no_return().
|
||||
|
||||
generate_id({constant, #bender_ConstantSchema{} = Schema}, WoodyCtx) ->
|
||||
NewInternalID = Schema#bender_ConstantSchema.internal_id,
|
||||
Constant = #constant{internal_id = NewInternalID},
|
||||
generate(Constant, WoodyCtx);
|
||||
|
||||
generate_id({sequence, #bender_SequenceSchema{} = Schema}, WoodyCtx) ->
|
||||
SequenceID = Schema#bender_SequenceSchema.sequence_id,
|
||||
Minimum = Schema#bender_SequenceSchema.minimum,
|
||||
Sequence = #sequence{id = SequenceID, minimum = Minimum},
|
||||
generate(Sequence, WoodyCtx);
|
||||
|
||||
generate_id({snowflake, #bender_SnowflakeSchema{}}, WoodyCtx) ->
|
||||
generate(snowflake, WoodyCtx);
|
||||
|
||||
generate_id(Schema, _WoodyCtx) ->
|
||||
erlang:error({unknown_schema, Schema}).
|
||||
|
||||
-spec generate(schema(), woody_context()) ->
|
||||
{ok, generate_id_result()} | no_return().
|
||||
|
||||
generate(Schema, WoodyCtx) ->
|
||||
case bender_generator:generate(Schema, WoodyCtx) of
|
||||
{ID, IntegerID} ->
|
||||
{ok, #bender_GeneratedID{
|
||||
id = ID,
|
||||
integer_id = IntegerID
|
||||
}};
|
||||
ID ->
|
||||
{ok, #bender_GeneratedID{
|
||||
id = ID
|
||||
}}
|
||||
end.
|
67
apps/bender/test/generator_client.erl
Normal file
67
apps/bender/test/generator_client.erl
Normal file
@ -0,0 +1,67 @@
|
||||
-module(generator_client).
|
||||
|
||||
-export([new/0]).
|
||||
-export([generate_id/2]).
|
||||
|
||||
-type client() :: woody_context:ctx().
|
||||
|
||||
-type schema() :: bender_thrift:'GenerationSchema'().
|
||||
|
||||
-define(retry_stategy, {linear, 5, 1000}).
|
||||
|
||||
%%% API
|
||||
|
||||
-spec new() ->
|
||||
client().
|
||||
|
||||
new() ->
|
||||
woody_context:new().
|
||||
|
||||
-spec generate_id(schema(), client()) ->
|
||||
woody:result() | no_return().
|
||||
|
||||
generate_id(Schema, Client) ->
|
||||
call('GenerateID', [Schema], Client).
|
||||
|
||||
%%% Internal functions
|
||||
|
||||
-spec call(atom(), list(), client()) ->
|
||||
woody:result() | no_return().
|
||||
|
||||
call(Function, Args, Client) ->
|
||||
Call = {{bender_thrift, 'Generator'}, Function, Args},
|
||||
Opts = #{
|
||||
url => <<"http://bender:8022/v1/generator">>,
|
||||
event_handler => scoper_woody_event_handler,
|
||||
transport_opts => #{
|
||||
max_connections => 10000
|
||||
}
|
||||
},
|
||||
call(Call, Opts, Client, ?retry_stategy).
|
||||
|
||||
call(Call, Opts, Client, Retry) ->
|
||||
try
|
||||
do_call(Call, Opts, Client)
|
||||
catch
|
||||
error:{woody_error, {_Source, Class, _Details}} = Error
|
||||
when Class =:= resource_unavailable orelse Class =:= result_unknown ->
|
||||
NextRetry = next_retry(Retry, Error),
|
||||
call(Call, Opts, Client, NextRetry)
|
||||
end.
|
||||
|
||||
do_call(Call, Opts, Client) ->
|
||||
case woody_client:call(Call, Opts, Client) of
|
||||
{ok, Response} ->
|
||||
Response;
|
||||
{exception, Exception} ->
|
||||
throw(Exception)
|
||||
end.
|
||||
|
||||
next_retry(Retry, Error) ->
|
||||
retry_step(genlib_retry:next_step(Retry), Error).
|
||||
|
||||
retry_step(finish, Error) ->
|
||||
erlang:error(Error);
|
||||
retry_step({wait, Timeout, Retry}, _) ->
|
||||
ok = timer:sleep(Timeout),
|
||||
Retry.
|
161
apps/bender/test/generator_tests_SUITE.erl
Normal file
161
apps/bender/test/generator_tests_SUITE.erl
Normal file
@ -0,0 +1,161 @@
|
||||
-module(generator_tests_SUITE).
|
||||
|
||||
-include_lib("common_test/include/ct.hrl").
|
||||
|
||||
-export([all/0]).
|
||||
-export([groups/0]).
|
||||
-export([init_per_suite/1]).
|
||||
-export([end_per_suite/1]).
|
||||
-export([init_per_testcase/2]).
|
||||
-export([end_per_testcase/2]).
|
||||
|
||||
-export([constant/1]).
|
||||
-export([sequence/1]).
|
||||
-export([sequence_minimum/1]).
|
||||
-export([snowflake/1]).
|
||||
|
||||
|
||||
-include_lib("bender_proto/include/bender_thrift.hrl").
|
||||
|
||||
-type config() :: [{atom(), term()}].
|
||||
-type group_name() :: atom().
|
||||
-type test_case_name() :: atom().
|
||||
|
||||
-define(config(Key, C), (element(2, lists:keyfind(Key, 1, C)))).
|
||||
|
||||
-spec all() ->
|
||||
[atom()].
|
||||
|
||||
all() ->
|
||||
[
|
||||
{group, main}
|
||||
].
|
||||
|
||||
-define(parallel_workers, 100).
|
||||
|
||||
-spec groups() -> [{group_name(), list(), [test_case_name()]}].
|
||||
|
||||
groups() ->
|
||||
[
|
||||
{main, [parallel], [
|
||||
sequence,
|
||||
sequence_minimum,
|
||||
constant,
|
||||
snowflake
|
||||
]}
|
||||
].
|
||||
|
||||
-spec init_per_suite(config()) ->
|
||||
config().
|
||||
|
||||
init_per_suite(C) ->
|
||||
Apps = genlib_app:start_application_with(scoper, [
|
||||
{storage, scoper_storage_logger}
|
||||
]) ++ genlib_app:start_application_with(bender, [
|
||||
{sequence, #{
|
||||
path => <<"/v1/stateproc/bender_sequence">>,
|
||||
schema => machinery_mg_schema_generic,
|
||||
url => <<"http://machinegun:8022/v1/automaton">>,
|
||||
event_handler => scoper_woody_event_handler,
|
||||
transport_opts => #{
|
||||
max_connections => 1000
|
||||
}
|
||||
}},
|
||||
{protocol_opts, #{
|
||||
timeout => 60000
|
||||
}},
|
||||
{transport_opts, #{
|
||||
max_connections => 10000,
|
||||
num_acceptors => 100
|
||||
}}
|
||||
]),
|
||||
[{suite_apps, Apps} | C].
|
||||
|
||||
-spec end_per_suite(config()) ->
|
||||
ok.
|
||||
|
||||
end_per_suite(C) ->
|
||||
genlib_app:stop_unload_applications(?config(suite_apps, C)).
|
||||
|
||||
-spec init_per_testcase(atom(), config()) ->
|
||||
config().
|
||||
|
||||
init_per_testcase(_Name, C) ->
|
||||
Client = generator_client:new(),
|
||||
[{client, Client} | C].
|
||||
|
||||
-spec end_per_testcase(atom(), config()) ->
|
||||
config().
|
||||
|
||||
end_per_testcase(_Name, _C) ->
|
||||
ok.
|
||||
|
||||
-spec constant(config()) ->
|
||||
ok.
|
||||
|
||||
constant(C) ->
|
||||
Client = get_client(C),
|
||||
InternalID = bender_utils:unique_id(),
|
||||
Schema = {constant, #bender_ConstantSchema{internal_id = InternalID}},
|
||||
InternalID = generate(Schema, Client),
|
||||
ok.
|
||||
|
||||
-spec sequence(config()) ->
|
||||
ok.
|
||||
|
||||
sequence(C) ->
|
||||
Client = get_client(C),
|
||||
SequenceID = bender_utils:unique_id(),
|
||||
ExpectedIDs = lists:seq(1, ?parallel_workers),
|
||||
GeneratedIDs = genlib_pmap:map(
|
||||
fun(_) ->
|
||||
Schema = {sequence, #bender_SequenceSchema{sequence_id = SequenceID}},
|
||||
{_, IntegerID} = generate(Schema, Client),
|
||||
IntegerID
|
||||
end,
|
||||
ExpectedIDs
|
||||
),
|
||||
ExpectedIDs = lists:sort(GeneratedIDs),
|
||||
ok.
|
||||
|
||||
-spec sequence_minimum(config()) ->
|
||||
ok.
|
||||
|
||||
sequence_minimum(C) ->
|
||||
Client = get_client(C),
|
||||
SequenceID = bender_utils:unique_id(),
|
||||
Schema1 = {sequence, #bender_SequenceSchema{sequence_id = SequenceID}},
|
||||
{<<"1">>, 1} = generate(Schema1, Client),
|
||||
Schema2 = {sequence, #bender_SequenceSchema{sequence_id = SequenceID, minimum = 4}},
|
||||
{<<"4">>, 4} = generate(Schema2, Client),
|
||||
OtherSeqID = bender_utils:unique_id(),
|
||||
Schema3 = {sequence, #bender_SequenceSchema{sequence_id = OtherSeqID, minimum = 8}},
|
||||
{<<"8">>, 8} = generate(Schema3, Client),
|
||||
ok.
|
||||
|
||||
-spec snowflake(config()) ->
|
||||
ok.
|
||||
|
||||
snowflake(C) ->
|
||||
Client = get_client(C),
|
||||
Schema = {snowflake, #bender_SnowflakeSchema{}},
|
||||
{_ID, _IntegerID} = generate(Schema, Client),
|
||||
ok.
|
||||
|
||||
|
||||
%%%
|
||||
|
||||
get_client(C) ->
|
||||
?config(client, C).
|
||||
|
||||
generate(Schema, Client) ->
|
||||
case generator_client:generate_id(Schema, Client) of
|
||||
#bender_GeneratedID{
|
||||
id = ID,
|
||||
integer_id = undefined
|
||||
} -> ID;
|
||||
#bender_GeneratedID{
|
||||
id = ID,
|
||||
integer_id = IntegerID
|
||||
} -> {ID, IntegerID}
|
||||
end.
|
@ -1,7 +1,8 @@
|
||||
[
|
||||
{bender, [
|
||||
{service, #{
|
||||
path => <<"/v1/bender">>
|
||||
{services, #{
|
||||
bender => #{path => <<"/v1/bender">>},
|
||||
generator => #{path => <<"/v1/generator">>}
|
||||
}},
|
||||
|
||||
{generator, #{
|
||||
|
@ -141,4 +141,4 @@
|
||||
rebar3_run
|
||||
]}.
|
||||
|
||||
%%{ct_readable, true}.
|
||||
%%{ct_readable, true}.
|
||||
|
@ -2,7 +2,7 @@
|
||||
[{<<"bear">>,{pkg,<<"bear">>,<<"0.8.7">>},2},
|
||||
{<<"bender_proto">>,
|
||||
{git,"git@github.com:rbkmoney/bender-proto.git",
|
||||
{ref,"df5bedd950dd2492e1760eceeb9207645b9af822"}},
|
||||
{ref,"0d5813b8a25c8d03e4e59e42aa5f4e9b785a3849"}},
|
||||
0},
|
||||
{<<"cache">>,{pkg,<<"cache">>,<<"2.2.0">>},1},
|
||||
{<<"certifi">>,{pkg,<<"certifi">>,<<"2.5.2">>},2},
|
||||
@ -22,7 +22,7 @@
|
||||
1},
|
||||
{<<"genlib">>,
|
||||
{git,"https://github.com/rbkmoney/genlib.git",
|
||||
{ref,"941b8c8d4dc544b740a2429ea8381c3873e5fe75"}},
|
||||
{ref,"1ca08793ad8af0beb26eda8cd00687c69f7ef8b4"}},
|
||||
0},
|
||||
{<<"gproc">>,{pkg,<<"gproc">>,<<"0.8.0">>},1},
|
||||
{<<"hackney">>,{pkg,<<"hackney">>,<<"1.16.0">>},1},
|
||||
|
Loading…
Reference in New Issue
Block a user