portunus_delayed_restart (portunus v0.8.0)
View SourceRate-limited restarts for plain Erlang/OTP supervisors, accepting the extended
supervisor2 restart type without a dependency on supervisor2.
mirrored_supervisor is built on rabbit's supervisor2, which accepts an
extended restart type {permanent, Delay} or {transient, Delay} (Delay
in seconds). A child spec ported from mirrored_supervisor can carry that
form; portunus runs elected children under a plain Erlang/OTP
supervisor, which rejects it.
child_spec/1 rewrites such a spec into a standard one whose start is
rate-limited to one attempt per Delay: an isolated crash restarts at
once, and only a restart within Delay of the previous attempt waits out
the remainder. This is not exactly supervisor2, which restarts
immediately until MaxR/MaxT is exceeded and only then delays on a timer;
the practical property migrated specs rely on (a one-off crash recovers
immediately while a crash loop is dampened) is the same. The wait runs in
the local supervisor's own process (a supervisor runs a child's start
synchronously), so a crash-looping child holds up the others under that
supervisor for up to Delay; the running pid is always the real child, so
introspection and links are unchanged.
Last-attempt timestamps live in one node-global ETS set owned by
portunus_sup, keyed by {LocalSup, ChildId} so entries are namespaced
per local supervisor; forget/2 clears one when the child is stopped, so
a later first start (for example after ownership moves back to this
node) is immediate.
Summary
Types
Accepted input: a standard child spec (passed through untouched), or one
carrying the extended restart, as a map or a supervisor2 tuple.
The extended supervisor2 restart: a standard type plus a delay in seconds
before a restart.
Functions
Clear the last-attempt marker so the next start of Id is immediate.
Clear every marker of a local supervisor that is going away.
Types
-type child_spec_in() :: supervisor:child_spec() | #{id := term(), start := mfargs(), restart := delayed_restart(), shutdown => timeout() | brutal_kill, type => worker | supervisor, modules => [module()] | dynamic} | {term(), mfargs(), delayed_restart(), timeout() | brutal_kill, worker | supervisor, [module()] | dynamic}.
Accepted input: a standard child spec (passed through untouched), or one
carrying the extended restart, as a map or a supervisor2 tuple.
-type delayed_restart() :: {permanent | transient, number()}.
The extended supervisor2 restart: a standard type plus a delay in seconds
before a restart.
Functions
-spec child_spec(child_spec_in()) -> supervisor:child_spec().
-spec ensure_table() -> ok.
Clear the last-attempt marker so the next start of Id is immediate.
-spec forget_all(pid()) -> ok.
Clear every marker of a local supervisor that is going away.