arcology-phx/arcology_app.org

110 lines
3.6 KiB
Org Mode

:PROPERTIES:
:ID: 20230303T100429.248407
:END:
#+TITLE: Arcology Elixir Backend Logic
#+AUTO_TANGLE: t
* Setting up the =Arcology= elixir module
This is a module, the submodules are where the interesting things happen. The module doc says what it does:
#+begin_src text :noweb-ref arcology.moduledoc
Arcology keeps the contexts that define your domain
and business logic.
Contexts are also responsible for managing your data, regardless
if it comes from the database, an external API or others.
#+end_src
#+begin_src elixir :tangle lib/arcology.ex :noweb yes
defmodule Arcology do
@moduledoc """
<<arcology.moduledoc>>
"""
end
#+end_src
* =Arcology.Application= Elixir Application Startup
#+begin_src elixir :tangle lib/arcology/application.ex :noweb yes
defmodule Arcology.Application do
@moduledoc false
use Application
<<start_2>>
<<config_change_3>>
end
#+end_src
So =Arcology.Application.start/2= is the entrypoint of the Phoenix [[https://hexdocs.pm/elixir/Application.html][OTP application]], it starts up a bunch of other *Supervised*[fn:1] Elixir processes and makes sure they keep running.
** =Arcology.Application.start/2=
We start the Ecto repository [[roam:Arcology.Repo]]:
#+begin_src elixir :noweb-ref app-children
Arcology.Repo
#+end_src
We start the PubSub messaging system:
#+begin_src elixir :noweb-ref app-children
{Phoenix.PubSub, name: Arcology.PubSub}
#+end_src
We start [[https://github.com/sneako/finch][Finch]], an HTTP client:
#+begin_src elixir :noweb-ref app-children
{Finch, name: Arcology.Finch}
#+end_src
We start the [[roam:ArcologyWeb.Endpoint]] which handles HTTP requests from the web.
#+begin_src elixir :noweb-ref app-children
ArcologyWeb.Endpoint
#+end_src
We will also start the =ArcologyWeb.Telemetry= server provided by Phoenix [n.b. this code block isn't directly included so that i can generate decent list-syntax without relying on metaprogramming or not being able to detangle this to my heart's content]
This supervisor is configured to only restart a single process when the process dies; for other applications you may want it to restart *all* children, or to only restart "younger" processes which may rely on state within the dead process. This is pretty simple for now. Check out [[https://hexdocs.pm/elixir/Supervisor.html][the docs]] if you care.
#+begin_src elixir :noweb-ref start_2 :noweb yes
@impl true
def start(_type, _args) do
children = [
ArcologyWeb.Telemetry
, <<app-children>>
]
opts = [strategy: :one_for_one, name: Arcology.Supervisor]
Supervisor.start_link(children, opts)
end
#+end_src
This =config_change= function is a stub that sends new configuration to the =ArcologyWeb.Endpoint= process when the appication is upgraded. I'll probably just restart the thing in place, but for highly-available OTP applications this sort of stuff is bread-and-butter.
#+begin_src elixir :noweb-ref config_change_3
@impl true
def config_change(changed, _new, removed) do
ArcologyWeb.Endpoint.config_change(changed, removed)
:ok
end
#+end_src
* =Arcology.Mailer=
This is a stub for now -- maybe i'll send mails for new posts in the future but *shrug*:
#+begin_src elixir :tangle lib/arcology/mailer.ex
defmodule Arcology.Mailer do
use Swoosh.Mailer, otp_app: :arcology
end
#+end_src
* Footnotes
[fn:1] Elixir is built on Erlang, and Erlang has a process-based Actor model, you can send messages to processes whose IDs you have. The Supervisor is responsible for starting and managing the lifecycle of these processes. See [[https://www.erlang.org/doc/design_principles/sup_princ.html][the OTP Design Principles]] doc.