Supervision
Copy MarkdownCalendrical runs two processes, both under Calendrical.Supervisor:
Calendrical.YearCacheowns the table in which the calendars reckoned by astronomy (the Persian, lunisolar and observational Islamic calendars) keep what they work out about a year.Calendrical.Compilercreates the calendars made at runtime, such as a territory's reform calendar or a calendar made withCalendrical.new/3, one at a time.
Once they are running, the supervisor registers Calendrical with Localize as the provider of its calendars, so that a locale's -u-ca- extension names a Calendrical calendar.
By default this supervisor is started when the :calendrical application starts, and there is nothing to do. This guide is for an application that prefers to start Calendrical in its own supervision tree, as Localize allows too, typically to control the order in which it starts relative to the application's own processes.
The default: started with the application
def deps do
[
{:calendrical, "~> 2.2"}
]
endThe :calendrical application starts at boot, after Localize and Astro, which it depends on, and Calendrical.Supervisor is its supervisor.
Supervising Calendrical yourself
Mark the dependency runtime: false, so that Mix compiles Calendrical but does not start it:
def deps do
[
{:calendrical, "~> 2.2", runtime: false}
]
endThen add Calendrical.Supervisor to the application's children. {Calendrical.Supervisor, []} is the same; there are no options.
defmodule MyApp.Application do
use Application
@impl true
def start(_type, _args) do
children = [
MyApp.Repo,
Localize.Supervisor,
Astro.Supervisor,
Calendrical.Supervisor,
MyAppWeb.Endpoint
]
Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)
end
endCalendrical's own dependencies
With Calendrical not started, neither are the applications it depends on, and its calendars need two of them:
Localize formats, parses and localizes dates. Start it with
Localize.Supervisor, as above, or depend on:localizedirectly so its application starts. Its supervision guide describes the first.Astro loads the JPL ephemeris that the calendars reckoned by astronomy compute from. List
Astro.SupervisorbeforeCalendrical.Supervisor, as above, to start it yourself. OtherwiseCalendrical.Supervisorstarts the:astroapplication as it starts, when neither that application norAstro.Supervisoris running, and returns{:error, {:astro_not_started, reason}}if it cannot, as when the ephemeris cannot be found.
Ordering
List Calendrical.Supervisor before any process that uses a calendar as it starts, and Astro.Supervisor, when you list it, before Calendrical.Supervisor. Starting Calendrical needs nothing from Localize, but using the calendars does, so list Localize.Supervisor before the processes that use them.
Releases
A dependency marked runtime: false is left out of a release unless the release names it. Name Calendrical to be loaded, which loads its dependencies with it:
def project do
[
app: :my_app,
releases: [
my_app: [applications: [calendrical: :load]]
]
]
endWhat happens when a process stops
Calendrical.Supervisor restarts a process that stops, each on its own. A restarted Calendrical.YearCache starts with an empty table, so the calendars work out each year again the first time they are asked about it. Their answers are the same.
Checking
Once the application is started, Calendrical.Supervisor is among its children, with Calendrical's processes below it:
iex> MyApp.Supervisor |> Supervisor.which_children() |> Enum.map(&elem(&1, 0))
[MyAppWeb.Endpoint, Calendrical.Supervisor, Astro.Supervisor, Localize.Supervisor, MyApp.Repo]
iex> Calendrical.Supervisor |> Supervisor.which_children() |> Enum.map(&elem(&1, 0))
[Calendrical.Compiler, Calendrical.YearCache]Starting Calendrical.Supervisor while the :calendrical application also runs fails with {:already_started, pid}, as the supervisor is registered under its name: use one or the other.
Which to choose
Starting with the application is right for almost every project. Supervising Calendrical yourself is right when it must start in a particular order relative to the application's own processes. Calendrical behaves the same either way: the same processes, the same cache and the same calendars.