2017-04-19 59 views
8

我正在使用phx 1.3和伞应用程序的新套件产品的体系结构。如何为许多应用程序构建凤凰伞框架

我有一个现有的基于凤凰的企业级WebRTC软电话(许多按键,一个显示器,多输入和输出音频设备选择,等等)。 我已经开发了一个与Phoenix的Slack克隆消息应用程序原型。 这两个应用程序都相当大 我需要将手机与聊天应用程序集成到一个前端,可能只是电话,聊天客户端和两者。 我将需要向前移动的聊天客户端添加很多新功能 我还希望架构支持使用相同的客户端在呼叫服务器(基于用户)以及潜在的大量管理员级别设置。 我也可能会在未来添加其他应用程序,如操作面板,日志查看器,并且列表继续... 客户端JS非常简单,没有前端框架。我渲染模板服务器端,并通过通道推送HTML。

我想构建这个可插件。相同的端点和数据库。一个普通的UX。

我想在这个保护伞中会有两个常见的应用程序,一个用于Phoenix端点和一个控制器,另一个用于主要的Repo和一对模式。我试图弄清楚为每个应用程序使用两个或多个附加应用程序是多么困难。一个用于上下文和模式,另一个用于控制器,视图,模板和早午餐资源。可能是另一个第三方API。

为了使这项工作,我需要在每个应用程序中为路由器动态分派。一种处理每个应用程序中包含的迁移的方法,可能更多的我还没有想过。

正如任何人试过这个?有没有类似结构的开源项目?

回答

8

我在日常工作中使用的elixir应用程序是一款带13个应用程序的雨伞。

根部是Phoenix端点和顶层路由器,它将请求转发给其他应用中定义的路由器。

这意味着该应用程序不会拆分为图层(网络/业务/数据),而是分为垂直域切片。

随着应用程序在过去12个月中的显着增长,这已经很好地扩展了。

我有最大的小问题,就是凤凰路由器转发到其他路由器时,从请求剥离最主要的路径,所以我们创建了一个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 

我们管理整个数据库的迁移在一个单一的应用程序只是为了简单,但外生架构是在每个应用程序另行申报。

Here是一个演示一些概念的项目。

+2

谢谢!我喜欢你的'mount'方法。我过去曾经遇到过这个问题。没有想到你的方法。不过,我用这个'Application.get_env(:app,:routers)|> Enum.map(&(forward“/”,&1))'试了一个快速秒杀''。我把它放在我的主路由器的末端,它似乎工作。你能想到这种方法的任何问题吗? –

+0

'垂直域切片'听起来不错。我已经看到了将persistence/db解压到它自己的应用程序'apps/db /'中的引用。你对此有何看法? – AdamT

+0

我看到你提到'我们为了简单而在一个应用程序中管理整个数据库的迁移。这个架构有没有问题? – AdamT

0

我也在研究一个相当大的伞应用程序。而不是维护一个配置了每个应用程序的入口点的文件,我想看看我能否让它更具动态性。所以我写了一个看起来像这样的插件:

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