Как структурировать каркас зонтика Phoenix для многих приложений
Я играю с архитектурой для нового набора продуктов с использованием phx 1.3 и зонтичных приложений.
У меня есть программный телефон WebRTC корпоративного класса на базе Phoenix (множество клавиш, дисплей, несколько аудио-устройств ввода и вывода и т. Д.). Я разработал прототип приложения для клонирования сообщений Slack с помощью Phoenix. Оба приложения довольно большие, мне нужно интегрировать телефон с приложением чата в один интерфейс, который может быть либо просто телефоном, либо клиентом чата, и обоими. Мне нужно будет добавить много новых функций в чат-клиент. Я также хочу, чтобы архитектура поддерживала использование одного и того же клиента для предоставления дополнительных настроек на сервере вызовов (на основе пользователей) и, возможно, большого количества настроек уровня администратора. Возможно, в будущем я добавлю и другие приложения, такие как панель оператора, средство просмотра журналов, и этот список можно продолжить... JS на стороне клиента довольно прост, нет фреймворка. Я отрисовываю шаблоны на стороне сервера и выдвигаю html по каналам.
Я хотел бы построить этот плагин. Та же конечная точка и база данных. Один общий UX.
Я думаю, что в центре будет два общих приложения: одно для конечной точки Phoenix и пара контроллеров, а другое для основного репо и пара схем. Я пытаюсь понять, насколько сложно будет использовать два или более дополнительных приложения для каждого приложения. Один для контекста и схемы, другой для контроллеров, представлений, шаблонов и ресурсов позднего завтрака. Возможно, другой для сторонних API.
Чтобы это работало, мне понадобится динамическая рассылка для маршрутизаторов в каждом приложении. Метод для обработки миграций, содержащихся в каждом из приложений, и, вероятно, больше, о чем я еще не думал.
Как кто-нибудь пробовал это? Есть ли проекты с открытым исходным кодом с похожей структурой?
2 ответа
Приложение с эликсиром, с которым я работаю каждый день, представляет собой зонтик с 13 приложениями.
В корне находится конечная точка Phoenix и маршрутизатор верхнего уровня, который пересылает запросы маршрутизаторам, определенным в других приложениях.
Это означает, что приложение не разбито на слои (сеть / бизнес / данные), а скорее на вертикальные доменные срезы.
Это хорошо масштабируется, так как приложение значительно выросло за последние 12 месяцев.
Самый большой недостаток, который у меня был, заключается в том, что маршрутизаторы Phoenix удаляют начальный путь из запроса при пересылке на другие маршрутизаторы, поэтому мы создали mount
макрос для использования с Plug
маршрутизатор, который сохраняет путь запроса без изменений:
defmodule MyApp.Router do
@moduledoc """
Top level routing to each of the sub-systems
"""
use Plug.Router
plug :match
plug :dispatch
mount "/events/*_", Events.Router
mount "/report/*_", Report.Router
mount "/stats/*_", Stats.Router
mount "/auth/*_", Auth.Router
end
и смонтировать:
defmacro mount(path, router, opts \\ []) do
quote do
@opts unquote(router).init(unquote(opts))
match unquote(path), do: unquote(router).call(var!(conn), @opts)
end
end
Мы просто осуществляем миграцию всей базы данных в одном приложении, но схемы Ecto объявляются в каждом приложении отдельно.
Вот проект, который демонстрирует некоторые концепции.
Я также работаю над довольно большим зонтичным приложением. Вместо того, чтобы поддерживать файл с настроенными точками входа для каждого приложения, я хотел посмотреть, смогу ли я сделать его более динамичным. Поэтому я написал плагин, который выглядит следующим образом:
def call(%{path_info: [path|_]} = conn, opts) do
path = path |> String.downcase() |> Macro.camelize()
module =
try do
Module.safe_concat [LocationRouting, path, Location]
rescue
_ -> nil
end
if module do
module.call(conn, opts)
else
conn
end
end
Я добавил этот штекер в конечную точку. И затем это до вызываемого модуля, который снова способен добавить маршрутизатор или что-то похожее на конечную точку с помощью Plug.Builder
Вы можете посмотреть полный пример здесь: https://github.com/tverlaan/location_routing