Skip to content

Commit 5accc10

Browse files
authored
Fix pins unrandomizing (#134)
* Add extra test to pins * Fix pins unrandomizing * Fix pins finally * Add test and docs
1 parent ef25bdc commit 5accc10

File tree

3 files changed

+118
-39
lines changed

3 files changed

+118
-39
lines changed

apps/routing/src/hg_routing.erl

Lines changed: 82 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -349,20 +349,31 @@ select_better_route({LeftScore, _} = Left, {RightScore, _} = Right) ->
349349
RightPin = RightScore#domain_PaymentRouteScores.route_pin,
350350
Res =
351351
case {LeftPin, RightPin} of
352-
_ when LeftPin /= ?ZERO, RightPin /= ?ZERO, LeftPin == RightPin ->
352+
_ when LeftPin /= ?ZERO, RightPin /= ?ZERO, RightPin == LeftPin ->
353353
select_better_pinned_route(Left, Right);
354354
_ ->
355355
select_better_regular_route(Left, Right)
356356
end,
357357
Res.
358358

359-
select_better_pinned_route({LeftScore0, _Route1} = Left, {RightScore0, _Route2} = Right) ->
359+
select_better_pinned_route({LeftScore0, LeftRoute} = Left, {RightScore0, RightRoute} = Right) ->
360360
LeftScore1 = LeftScore0#domain_PaymentRouteScores{
361-
random_condition = 0
361+
random_condition = 0,
362+
route_pin = erlang:phash2({
363+
LeftScore0#domain_PaymentRouteScores.route_pin,
364+
hg_route:provider_ref(LeftRoute),
365+
hg_route:terminal_ref(LeftRoute)
366+
})
362367
},
363368
RightScore1 = RightScore0#domain_PaymentRouteScores{
364-
random_condition = 0
369+
random_condition = 0,
370+
route_pin = erlang:phash2({
371+
RightScore0#domain_PaymentRouteScores.route_pin,
372+
hg_route:provider_ref(RightRoute),
373+
hg_route:terminal_ref(RightRoute)
374+
})
365375
},
376+
366377
case max(LeftScore1, RightScore1) of
367378
LeftScore1 ->
368379
Left;
@@ -868,58 +879,93 @@ pin_random_test() ->
868879
Route2 = {hg_route:new(?prv(2), ?trm(2), 50, 1, Pin), Scores},
869880
lists:foldl(
870881
fun(_I, Acc) ->
871-
BalancedRoutes = balance_routes([Route1, Route2]),
872-
ScoredRoutes = score_routes(BalancedRoutes),
873-
{{_, ChosenScoredRoute}, _IdealRoute} = find_best_routes(ScoredRoutes),
882+
{ST, _} = ShuffledRoute = shuffle_routes([Route1, Route2]),
874883
case Acc of
875884
undefined ->
876-
ChosenScoredRoute;
885+
ShuffledRoute;
886+
{ST, _} ->
887+
ShuffledRoute;
877888
_ ->
878-
ChosenTerminal = hg_route:terminal_ref(ChosenScoredRoute),
879-
AccTerminal = hg_route:terminal_ref(Acc),
880-
_ = ?assertEqual(ChosenTerminal, AccTerminal),
881-
ChosenScoredRoute
889+
error({ShuffledRoute, Acc})
882890
end
883891
end,
884892
undefined,
885893
lists:seq(0, 1000)
886894
).
887895

896+
-spec diff_pin_test() -> _.
897+
diff_pin_test() ->
898+
Pin = #{
899+
email => <<"example@mail.com">>
900+
},
901+
Scores = {{alive, 0.0}, {normal, 0.0}},
902+
Route1 = {hg_route:new(?prv(1), ?trm(1), 50, 33, Pin), Scores},
903+
Route2 = {hg_route:new(?prv(1), ?trm(2), 50, 33, Pin), Scores},
904+
Route3 = {hg_route:new(?prv(1), ?trm(3), 50, 33, Pin#{client_ip => <<"IP">>}), Scores},
905+
{I1, I2, I3} = lists:foldl(
906+
fun(_I, {Iter1, Iter2, Iter3}) ->
907+
{ST, _} = shuffle_routes([Route1, Route2, Route3]),
908+
case ST of
909+
?trm(1) ->
910+
{Iter1 + 1, Iter2, Iter3};
911+
?trm(2) ->
912+
{Iter1, Iter2 + 1, Iter3};
913+
?trm(3) ->
914+
{Iter1, Iter2, Iter3 + 1}
915+
end
916+
end,
917+
{0, 0, 0},
918+
lists:seq(0, 1000)
919+
),
920+
case {I1, I2} of
921+
{0, S} when S > 400 ->
922+
true;
923+
{S, 0} when S > 400 ->
924+
true;
925+
SomethingElse ->
926+
error({{i1, i2}, SomethingElse})
927+
end,
928+
case I3 of
929+
_ when I3 > 300 ->
930+
true;
931+
_ ->
932+
error({i3, I3})
933+
end.
934+
888935
-spec pin_weight_test() -> _.
889936
pin_weight_test() ->
890937
Pin0 = #{
891938
email => <<"example@mail.com">>
892939
},
893940
Pin1 = #{
894-
email => <<"example2@mail.com">>
941+
email => <<"example1@mail.com">>
895942
},
896-
Scores = {{alive, 0.0}, {normal, 0.0}},
897-
Route1 = {hg_route:new(?prv(1), ?trm(1), 50, 1, Pin0), Scores},
898-
Route2 = {hg_route:new(?prv(2), ?trm(2), 50, 1, Pin1), Scores},
899-
{_, DiffTimes} = lists:foldl(
900-
fun(_I, {Acc, Iter}) ->
901-
BalancedRoutes = balance_routes([Route1, Route2]),
902-
ScoredRoutes = score_routes(BalancedRoutes),
903-
{{_, ChosenScoredRoute}, _IdealRoute} = find_best_routes(ScoredRoutes),
904-
case Acc of
905-
undefined ->
906-
{ChosenScoredRoute, Iter};
943+
Scores1 = {{alive, 0.0}, {normal, 0.0}},
944+
Scores2 = {{alive, 0.0}, {normal, 0.0}},
945+
Route1 = {hg_route:new(?prv(1), ?trm(1), 50, 1, Pin0, ?fd_overrides(true)), Scores1},
946+
Route2 = {hg_route:new(?prv(1), ?trm(2), 50, 1, Pin0, ?fd_overrides(true)), Scores2},
947+
Route3 = {hg_route:new(?prv(1), ?trm(1), 50, 1, Pin1, ?fd_overrides(true)), Scores1},
948+
Route4 = {hg_route:new(?prv(1), ?trm(2), 50, 1, Pin1, ?fd_overrides(true)), Scores2},
949+
true = lists:foldl(
950+
fun(_I, _A) ->
951+
{ShuffledRoute1, _} = shuffle_routes([Route1, Route2]),
952+
{ShuffledRoute2, _} = shuffle_routes([Route3, Route4]),
953+
case true of
954+
_ when ShuffledRoute1 == ?trm(1), ShuffledRoute2 == ?trm(2) ->
955+
true;
907956
_ ->
908-
ChosenTerminal = hg_route:terminal_ref(ChosenScoredRoute),
909-
case hg_route:terminal_ref(Acc) of
910-
ChosenTerminal ->
911-
{Acc, Iter};
912-
_ ->
913-
{Acc, Iter + 1}
914-
end
957+
error({ShuffledRoute1, ShuffledRoute2})
915958
end
916959
end,
917-
{undefined, 0},
960+
true,
918961
lists:seq(0, 1000)
919-
),
920-
?assertNotEqual(0, DiffTimes),
921-
?assertEqual(true, DiffTimes > 300),
922-
?assertEqual(true, DiffTimes < 700).
962+
).
963+
964+
shuffle_routes(Routes) ->
965+
BalancedRoutes = balance_routes(Routes),
966+
ScoredRoutes = score_routes(BalancedRoutes),
967+
{{_, ChosenScoredRoute}, _IdealRoute} = find_best_routes(ScoredRoutes),
968+
{hg_route:terminal_ref(ChosenScoredRoute), ChosenScoredRoute}.
923969

924970
-spec balance_routes_test_() -> [testcase()].
925971
balance_routes_test_() ->

doc/index.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
# Документация
22

3-
1. [Общее описание](overview.md)
4-
1. [Установка](install.md)
5-
1. [Первоначалная настройка](configuration.md)
3+
1. [Работа пинов](route_pins.md)

doc/route_pins.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Пины роутов
2+
3+
## Какая задача
4+
5+
У нас есть 2 и более роутов с одинаковым приоритетом
6+
и какой-то там разбивкой по весу. Например 3 роута с весами 33:33:33.
7+
8+
К нам приходит плательщик. Он оплачивает какую-то услугу
9+
и этот платеж проходит через конкретный терминал конкретного провайдера.
10+
Проще говоря он выбрал один из кандидатов (роутов) из списка с одинаковым приоритетом.
11+
12+
Теперь мы хотим чтобы этот плательщик в будущем ходим через тот же самый роут.
13+
14+
Плательщика определяем каким-то там способом.
15+
16+
## Решение
17+
18+
Мы в каждом роут кандидате можем указать
19+
[список характеристик](https://github.com/valitydev/damsel/blob/master/proto/domain.thrift#L2850-L2856)
20+
по которым мы будем определять какой именно плательщик к нам пришел.
21+
22+
Когда к нам приходит запрос на проведение платежа, то мы собираем все указанные
23+
в конкретном кандидате характеристики и вычисляем хэш этих характеристик.
24+
Этот хэш учитывается при сортировке роутов по самым желаемым.
25+
26+
Если как в примере выше у нас 3 роут кандидата с одинаковым весом
27+
и список характеристик (например смотрим только на имейл) совпадает,
28+
то мы лочим роут с этим значением характеристики.
29+
Все последующие платежи с этими значениями будут проходить по тому роуту, что был использован
30+
в первой операции. Соответственно вес у нас в одном приоритете становится 100:0:0.
31+
32+
Если же один из этих роутов имеет другой набор характеристик, например имейл и IP адрес клиента, то он участвует
33+
в локе пинов с роутами у которых такой же набор характеристик. В данном примере, так как он один, то распределение
34+
становится 66:0:33. Если бы был еще один роут с тем же приоритетом и набором характеристик имейл и IP, то
35+
распределение было бы 50:0:50:0

0 commit comments

Comments
 (0)