I spent the better half of the last month researching, architecting and implementing the process architecture for Juvet. This is an important step when building Elixir applications since every bot in Juvet will be a process with state.
A lot of the concepts in this architecture was modeled after the logic within The Little Elixir & OTP Guidebook.
Starting the Juvet Application, the following processes are started up:
-
Juvet (Application)TheApplicationmodule for the whole Juvet application. This just starts theBotFactorySupervisorand passes the application configuration forJuvetas the only argument. -
BotFactory (Supervisor)ASupervisorthat is started by theJuvetApplication. It receives the application configuration as aKeywordlist as it’s only argument. TheBotFactoryis used to create and start additional bot processes through theSuperintendent. On initialize, theBotFactorystarts aSuperintendentas it’s only child using theone_for_allstrategy, passing in the config. If theSuperintendentprocess dies, then everything else should be restarted since it is the brains of the factory. -
Superintendent (GenServer)AGenServerprocess that is started by theBotFactorywith the application config as it’s only argument. TheSuperintendentis the “brains” of the factory and helps it keep running. If theSuperintendentis started with valid configuration, it allows the rest of the factory to start up. It starts anEndpointprocess and aFactorySupervisorunder theBotFactorySupervisorif the configuration is valid.
If the configuration is valid, then the FactorySupervisor and Endpoint are started up under the BotFactory Supervisor:
-
FactorySupervisor (Supervisor)ASupervisorthat will supervise all the bot processes within the factory. It can add bot processes (under aBotSupervisor) with it’s functions. -
Endpoint (Supervisor)ThisSupervisorstarts aRanch Listenterwhich is responsible for receiving incoming bot messages from the platforms. For example, Slack will send it’s events, actions, and menu requests to theranch_listenerchild process. -
EndpointRouter (Ranch Listener)TheModulethat sets up the routes to the platform endpoints based on the application configuration.
A bot can be added to the supervision tree with the following function:
{:ok, bot} = Juvet.create_bot(:my_bot_1)
When a bot is added to the process architecture, the process architecture now adds a BotSupervisor and a Bot underneath the FactorySupervisor. Obviously more than one can be added. There will be one supervisor and one process for each new team that is added.
-
BotSupervisor (Supervisor)ASupervisorthat supports theBotprocess and any additional processes like aSlackRTMReceiverwhich can listen for incoming messages on a websocket for that particular bot process. -
Bot (GenServer)AGenServerprocess that handles incoming and outgoing messages to and from various services. It holds onto conversations within it’s own state for each individual platform and team.
If the bot is connected to the Slack RTM, a listener is created under the BotSupervisor and next to the Bot process. This can be added to the BotSupervisor with the following function:
Juvet.connect_bot(bot, :slack_rtm, %{token: "MY_TOKEN", team_id: "T123456"})
-
SlackRTMReceiver (GenServer)AGenServerprocess that connects to Slack via it’s RTM API and routes incoming and outgoing messages to theBot.
Time will tell if this is the correct foundation to build an army of bots on. If this was helpful to you or you have suggestions, please email me at jamie AT brilliantfantastic.com. If you are interested in helping build an army of bots, check out my GitHub sponsor page.




Top comments (0)