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)
TheApplication
module for the whole Juvet application. This just starts theBotFactory
Supervisor
and passes the application configuration forJuvet
as the only argument. -
BotFactory (Supervisor)
ASupervisor
that is started by theJuvet
Application
. It receives the application configuration as aKeyword
list as it’s only argument. TheBotFactory
is used to create and start additional bot processes through theSuperintendent
. On initialize, theBotFactory
starts aSuperintendent
as it’s only child using theone_for_all
strategy, passing in the config. If theSuperintendent
process dies, then everything else should be restarted since it is the brains of the factory. -
Superintendent (GenServer)
AGenServer
process that is started by theBotFactory
with the application config as it’s only argument. TheSuperintendent
is the “brains” of the factory and helps it keep running. If theSuperintendent
is started with valid configuration, it allows the rest of the factory to start up. It starts anEndpoint
process and aFactorySupervisor
under theBotFactory
Supervisor
if the configuration is valid.
If the configuration is valid, then the FactorySupervisor
and Endpoint
are started up under the BotFactory
Supervisor
:
-
FactorySupervisor (Supervisor)
ASupervisor
that will supervise all the bot processes within the factory. It can add bot processes (under aBotSupervisor
) with it’s functions. -
Endpoint (Supervisor)
ThisSupervisor
starts aRanch Listenter
which is responsible for receiving incoming bot messages from the platforms. For example, Slack will send it’s events, actions, and menu requests to theranch_listener
child process. -
EndpointRouter (Ranch Listener)
TheModule
that 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)
ASupervisor
that supports theBot
process and any additional processes like aSlackRTMReceiver
which can listen for incoming messages on a websocket for that particular bot process. -
Bot (GenServer)
AGenServer
process 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)
AGenServer
process 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)