mirror of
https://github.com/valitydev/hellgate.git
synced 2024-11-06 02:45:20 +00:00
Fix pins unrandomizing (#134)
* Add extra test to pins * Fix pins unrandomizing * Fix pins finally * Add test and docs
This commit is contained in:
parent
ef25bdc20a
commit
5accc10b24
@ -349,20 +349,31 @@ select_better_route({LeftScore, _} = Left, {RightScore, _} = Right) ->
|
|||||||
RightPin = RightScore#domain_PaymentRouteScores.route_pin,
|
RightPin = RightScore#domain_PaymentRouteScores.route_pin,
|
||||||
Res =
|
Res =
|
||||||
case {LeftPin, RightPin} of
|
case {LeftPin, RightPin} of
|
||||||
_ when LeftPin /= ?ZERO, RightPin /= ?ZERO, LeftPin == RightPin ->
|
_ when LeftPin /= ?ZERO, RightPin /= ?ZERO, RightPin == LeftPin ->
|
||||||
select_better_pinned_route(Left, Right);
|
select_better_pinned_route(Left, Right);
|
||||||
_ ->
|
_ ->
|
||||||
select_better_regular_route(Left, Right)
|
select_better_regular_route(Left, Right)
|
||||||
end,
|
end,
|
||||||
Res.
|
Res.
|
||||||
|
|
||||||
select_better_pinned_route({LeftScore0, _Route1} = Left, {RightScore0, _Route2} = Right) ->
|
select_better_pinned_route({LeftScore0, LeftRoute} = Left, {RightScore0, RightRoute} = Right) ->
|
||||||
LeftScore1 = LeftScore0#domain_PaymentRouteScores{
|
LeftScore1 = LeftScore0#domain_PaymentRouteScores{
|
||||||
random_condition = 0
|
random_condition = 0,
|
||||||
|
route_pin = erlang:phash2({
|
||||||
|
LeftScore0#domain_PaymentRouteScores.route_pin,
|
||||||
|
hg_route:provider_ref(LeftRoute),
|
||||||
|
hg_route:terminal_ref(LeftRoute)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
RightScore1 = RightScore0#domain_PaymentRouteScores{
|
RightScore1 = RightScore0#domain_PaymentRouteScores{
|
||||||
random_condition = 0
|
random_condition = 0,
|
||||||
|
route_pin = erlang:phash2({
|
||||||
|
RightScore0#domain_PaymentRouteScores.route_pin,
|
||||||
|
hg_route:provider_ref(RightRoute),
|
||||||
|
hg_route:terminal_ref(RightRoute)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
case max(LeftScore1, RightScore1) of
|
case max(LeftScore1, RightScore1) of
|
||||||
LeftScore1 ->
|
LeftScore1 ->
|
||||||
Left;
|
Left;
|
||||||
@ -868,58 +879,93 @@ pin_random_test() ->
|
|||||||
Route2 = {hg_route:new(?prv(2), ?trm(2), 50, 1, Pin), Scores},
|
Route2 = {hg_route:new(?prv(2), ?trm(2), 50, 1, Pin), Scores},
|
||||||
lists:foldl(
|
lists:foldl(
|
||||||
fun(_I, Acc) ->
|
fun(_I, Acc) ->
|
||||||
BalancedRoutes = balance_routes([Route1, Route2]),
|
{ST, _} = ShuffledRoute = shuffle_routes([Route1, Route2]),
|
||||||
ScoredRoutes = score_routes(BalancedRoutes),
|
|
||||||
{{_, ChosenScoredRoute}, _IdealRoute} = find_best_routes(ScoredRoutes),
|
|
||||||
case Acc of
|
case Acc of
|
||||||
undefined ->
|
undefined ->
|
||||||
ChosenScoredRoute;
|
ShuffledRoute;
|
||||||
|
{ST, _} ->
|
||||||
|
ShuffledRoute;
|
||||||
_ ->
|
_ ->
|
||||||
ChosenTerminal = hg_route:terminal_ref(ChosenScoredRoute),
|
error({ShuffledRoute, Acc})
|
||||||
AccTerminal = hg_route:terminal_ref(Acc),
|
|
||||||
_ = ?assertEqual(ChosenTerminal, AccTerminal),
|
|
||||||
ChosenScoredRoute
|
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
undefined,
|
undefined,
|
||||||
lists:seq(0, 1000)
|
lists:seq(0, 1000)
|
||||||
).
|
).
|
||||||
|
|
||||||
|
-spec diff_pin_test() -> _.
|
||||||
|
diff_pin_test() ->
|
||||||
|
Pin = #{
|
||||||
|
email => <<"example@mail.com">>
|
||||||
|
},
|
||||||
|
Scores = {{alive, 0.0}, {normal, 0.0}},
|
||||||
|
Route1 = {hg_route:new(?prv(1), ?trm(1), 50, 33, Pin), Scores},
|
||||||
|
Route2 = {hg_route:new(?prv(1), ?trm(2), 50, 33, Pin), Scores},
|
||||||
|
Route3 = {hg_route:new(?prv(1), ?trm(3), 50, 33, Pin#{client_ip => <<"IP">>}), Scores},
|
||||||
|
{I1, I2, I3} = lists:foldl(
|
||||||
|
fun(_I, {Iter1, Iter2, Iter3}) ->
|
||||||
|
{ST, _} = shuffle_routes([Route1, Route2, Route3]),
|
||||||
|
case ST of
|
||||||
|
?trm(1) ->
|
||||||
|
{Iter1 + 1, Iter2, Iter3};
|
||||||
|
?trm(2) ->
|
||||||
|
{Iter1, Iter2 + 1, Iter3};
|
||||||
|
?trm(3) ->
|
||||||
|
{Iter1, Iter2, Iter3 + 1}
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
{0, 0, 0},
|
||||||
|
lists:seq(0, 1000)
|
||||||
|
),
|
||||||
|
case {I1, I2} of
|
||||||
|
{0, S} when S > 400 ->
|
||||||
|
true;
|
||||||
|
{S, 0} when S > 400 ->
|
||||||
|
true;
|
||||||
|
SomethingElse ->
|
||||||
|
error({{i1, i2}, SomethingElse})
|
||||||
|
end,
|
||||||
|
case I3 of
|
||||||
|
_ when I3 > 300 ->
|
||||||
|
true;
|
||||||
|
_ ->
|
||||||
|
error({i3, I3})
|
||||||
|
end.
|
||||||
|
|
||||||
-spec pin_weight_test() -> _.
|
-spec pin_weight_test() -> _.
|
||||||
pin_weight_test() ->
|
pin_weight_test() ->
|
||||||
Pin0 = #{
|
Pin0 = #{
|
||||||
email => <<"example@mail.com">>
|
email => <<"example@mail.com">>
|
||||||
},
|
},
|
||||||
Pin1 = #{
|
Pin1 = #{
|
||||||
email => <<"example2@mail.com">>
|
email => <<"example1@mail.com">>
|
||||||
},
|
},
|
||||||
Scores = {{alive, 0.0}, {normal, 0.0}},
|
Scores1 = {{alive, 0.0}, {normal, 0.0}},
|
||||||
Route1 = {hg_route:new(?prv(1), ?trm(1), 50, 1, Pin0), Scores},
|
Scores2 = {{alive, 0.0}, {normal, 0.0}},
|
||||||
Route2 = {hg_route:new(?prv(2), ?trm(2), 50, 1, Pin1), Scores},
|
Route1 = {hg_route:new(?prv(1), ?trm(1), 50, 1, Pin0, ?fd_overrides(true)), Scores1},
|
||||||
{_, DiffTimes} = lists:foldl(
|
Route2 = {hg_route:new(?prv(1), ?trm(2), 50, 1, Pin0, ?fd_overrides(true)), Scores2},
|
||||||
fun(_I, {Acc, Iter}) ->
|
Route3 = {hg_route:new(?prv(1), ?trm(1), 50, 1, Pin1, ?fd_overrides(true)), Scores1},
|
||||||
BalancedRoutes = balance_routes([Route1, Route2]),
|
Route4 = {hg_route:new(?prv(1), ?trm(2), 50, 1, Pin1, ?fd_overrides(true)), Scores2},
|
||||||
ScoredRoutes = score_routes(BalancedRoutes),
|
true = lists:foldl(
|
||||||
{{_, ChosenScoredRoute}, _IdealRoute} = find_best_routes(ScoredRoutes),
|
fun(_I, _A) ->
|
||||||
case Acc of
|
{ShuffledRoute1, _} = shuffle_routes([Route1, Route2]),
|
||||||
undefined ->
|
{ShuffledRoute2, _} = shuffle_routes([Route3, Route4]),
|
||||||
{ChosenScoredRoute, Iter};
|
case true of
|
||||||
|
_ when ShuffledRoute1 == ?trm(1), ShuffledRoute2 == ?trm(2) ->
|
||||||
|
true;
|
||||||
_ ->
|
_ ->
|
||||||
ChosenTerminal = hg_route:terminal_ref(ChosenScoredRoute),
|
error({ShuffledRoute1, ShuffledRoute2})
|
||||||
case hg_route:terminal_ref(Acc) of
|
|
||||||
ChosenTerminal ->
|
|
||||||
{Acc, Iter};
|
|
||||||
_ ->
|
|
||||||
{Acc, Iter + 1}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
{undefined, 0},
|
true,
|
||||||
lists:seq(0, 1000)
|
lists:seq(0, 1000)
|
||||||
),
|
).
|
||||||
?assertNotEqual(0, DiffTimes),
|
|
||||||
?assertEqual(true, DiffTimes > 300),
|
shuffle_routes(Routes) ->
|
||||||
?assertEqual(true, DiffTimes < 700).
|
BalancedRoutes = balance_routes(Routes),
|
||||||
|
ScoredRoutes = score_routes(BalancedRoutes),
|
||||||
|
{{_, ChosenScoredRoute}, _IdealRoute} = find_best_routes(ScoredRoutes),
|
||||||
|
{hg_route:terminal_ref(ChosenScoredRoute), ChosenScoredRoute}.
|
||||||
|
|
||||||
-spec balance_routes_test_() -> [testcase()].
|
-spec balance_routes_test_() -> [testcase()].
|
||||||
balance_routes_test_() ->
|
balance_routes_test_() ->
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
# Документация
|
# Документация
|
||||||
|
|
||||||
1. [Общее описание](overview.md)
|
1. [Работа пинов](route_pins.md)
|
||||||
1. [Установка](install.md)
|
|
||||||
1. [Первоначалная настройка](configuration.md)
|
|
||||||
|
35
doc/route_pins.md
Normal file
35
doc/route_pins.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# Пины роутов
|
||||||
|
|
||||||
|
## Какая задача
|
||||||
|
|
||||||
|
У нас есть 2 и более роутов с одинаковым приоритетом
|
||||||
|
и какой-то там разбивкой по весу. Например 3 роута с весами 33:33:33.
|
||||||
|
|
||||||
|
К нам приходит плательщик. Он оплачивает какую-то услугу
|
||||||
|
и этот платеж проходит через конкретный терминал конкретного провайдера.
|
||||||
|
Проще говоря он выбрал один из кандидатов (роутов) из списка с одинаковым приоритетом.
|
||||||
|
|
||||||
|
Теперь мы хотим чтобы этот плательщик в будущем ходим через тот же самый роут.
|
||||||
|
|
||||||
|
Плательщика определяем каким-то там способом.
|
||||||
|
|
||||||
|
## Решение
|
||||||
|
|
||||||
|
Мы в каждом роут кандидате можем указать
|
||||||
|
[список характеристик](https://github.com/valitydev/damsel/blob/master/proto/domain.thrift#L2850-L2856)
|
||||||
|
по которым мы будем определять какой именно плательщик к нам пришел.
|
||||||
|
|
||||||
|
Когда к нам приходит запрос на проведение платежа, то мы собираем все указанные
|
||||||
|
в конкретном кандидате характеристики и вычисляем хэш этих характеристик.
|
||||||
|
Этот хэш учитывается при сортировке роутов по самым желаемым.
|
||||||
|
|
||||||
|
Если как в примере выше у нас 3 роут кандидата с одинаковым весом
|
||||||
|
и список характеристик (например смотрим только на имейл) совпадает,
|
||||||
|
то мы лочим роут с этим значением характеристики.
|
||||||
|
Все последующие платежи с этими значениями будут проходить по тому роуту, что был использован
|
||||||
|
в первой операции. Соответственно вес у нас в одном приоритете становится 100:0:0.
|
||||||
|
|
||||||
|
Если же один из этих роутов имеет другой набор характеристик, например имейл и IP адрес клиента, то он участвует
|
||||||
|
в локе пинов с роутами у которых такой же набор характеристик. В данном примере, так как он один, то распределение
|
||||||
|
становится 66:0:33. Если бы был еще один роут с тем же приоритетом и набором характеристик имейл и IP, то
|
||||||
|
распределение было бы 50:0:50:0
|
Loading…
Reference in New Issue
Block a user