Erlang TCP сервер голосования ногами

Я пытаюсь написать простую опцию голосования, чтобы добавить на свой существующий сервер.

У меня есть маршрутизатор сообщений, использующий gen_server, и он хранит все подключенные клиенты, используя init([]) -> {ok, dict:new()}, Маршрутизатор отделен от tcp-сервера, который также является gen_server, но обрабатывает tcp-запросы, которые затем передаются на маршрутизатор.

Поскольку "вещи" обрабатываются / хранятся отдельно, я хочу сохранить пользователя, которого ударили, список избирателей и его успех. Таким образом, это должно быть в некоторой степени глобальным, по крайней мере, внутри маршрутизатора, и в идеале отделять его от клиентов.

Есть идеи о лучшем / идеальном подходе?
Я полагаю, что мог бы создать еще один "маршрутизатор" gen_server, который будет хранить людей для записи в структуре записи {kick, {Votes, Passed}}, но я не знаю, идеально ли это.

1 ответ

Решение

Вы хотите "идентификатор пользователя, список избирателей и результаты". Давайте посмотрим, как это выглядит как кортеж:

{User :: user_id(), [Voters :: user_id()], Outcome :: boolean()}

Не так сложно Список этих кортежей - тоже не сложно. Суть их немного сложнее, потому что вы попадаете (по сути, если бы это был проплист, используя приведенные выше типы):

{User, {[Voters], Outcome}}

С которым чуть менее приятно иметь дело. Например, вы можете фильтровать результаты, но теперь они находятся внутри кортежа внутри кортежа, тогда как список плоских кортежей допускает простую фильтрацию (либо реальный фильтр, либо просто защиту понимания списка, либо что угодно) или использование lists:keysearch/3, Это делает сложные поиски более неловкими, особенно если вы хотите знать, сколько раз тот или иной избиратель голосовал, чтобы кого-то выгнать.

Основная проблема, безусловно, может быть облегчена с помощью ETS, поскольку она имеет средства для полной обработки кортежей гораздо быстрее, чем списки, использующие кортежи. keysearch/3 (и я предполагаю, что у вас есть тысячи и тысячи случаев, так что списки кортежей неадекватны - но, как всегда, попробуйте сначала так, вы можете обнаружить, что списки кортежей абсолютно адекватны!). С другой стороны, если случаи поиска становятся даже немного более сложными, или случаи должны храниться длительно и по-прежнему извлекать выгоду из манипуляций в памяти, или вам нужно несколько индексов и т. Д., Тогда вы действительно должны перейти к Mnesia.

Помимо этого... вы имеете дело с вложенными данными, и, хотя на самом деле это хорошо в 90% случаев, в другие 10% времени вы либо переизобретаете реляционные данные (но хуже, с меньшей фактической полезностью и медленнее).) или просто мучиться с кучей процедурного кода в стиле барокко, чтобы получить эффект, который можно получить бесплатно, без особой боли, просто используя что-то вроде Postgres (я очень хорошо знаком с этой БД, так что для меня это "легковесное решение") "- Я так понимаю, это не так для всех).

Для справки, ваши данные при разложении выглядят так (при условии, что идентификаторы пользователей являются адресами электронной почты для примера):

table user
  attributes
    id       EmailAddress
  conditions
    pk id

table kick
  attributes
    id       UUID
    user     EmailAddress
    outcome  Boolean
  conditions
    pk id
    fk user

table vote
  attributes
    kick     UUID
    user     EmailAddress
  conditions
    pk (kick user)
    fk kick
    fk user

Хотя очевидно, что User а также [Voter] Компоненты кортежей, описанных выше, ссылаются на записи пользователей, не так очевидно, почему попытка получить список всех голосов, отданных определенным пользователем с помощью кортежей, является таким неприятным процессом. Когда мы смотрим на разложенные данные, мы понимаем, что это три таблицы, и мы действительно хотим, чтобы мы могли выполнить запрос на vote один, если у вас есть это требование. Но если у вас нет этого требования, не беспокойтесь об этом, просто используйте кортежи в ETS или Mnesia!:-) Эти данные довольно крошечные в Эрланге.

Другие вопросы по тегам