Deferred startup deadlock detection.
handle_continue/2 runs after init/1 returns, so a sync call from
inside handle_continue does NOT block the parent supervisor — that's
why this is a separate analysis from sync_call_in_init. But three
specific patterns make handle_continue sync calls genuinely problematic:
- Mutual continue cycle —
A.handle_continuesync-callsB,B.handle_continuesync-callsA. Both processes return from init, the supervisor proceeds, but neither child ever processes its mailbox. - Continue calls later sibling — under
:one_for_one, calling a sibling that starts at a later position in the supervisor's child list races against that sibling's startup. - Continue calls parent supervisor — calling
Supervisor.which_children/1on the parent while it's still mid-start_link. The supervisor isn't reading its mailbox yet.
Plus a defensive variant: when the continue body is wrapped in
try/catch :exit, _, the literal deadlock is suppressed but the
worker enters a supervisor restart loop.
Output relations
mutual_continue_deadlock(mod_a, mod_b)— both modules' continues sync-call each other.continue_to_later_sibling(sup, caller, callee, caller_pos, callee_pos)— caller's continue sync-calls a sibling started later in the same supervisor.continue_to_parent_supervisor(worker, sup)— worker's continue sync-calls back into its parent supervisor.continue_crash_loop_risk(sup, worker)— defensive try/catch around the call converts the deadlock into a supervisor restart loop.init_timeout_deferral(mod, site, timeout_ms)— init/1 returns{:ok, state, timeout}; the work behind:timeoutis cancelled by any message that arrives first.
Finding severities
mutual_continue_deadlock—:error. Both processes block before ever reading their mailboxes; neither can answer the other, by construction.init_timeout_deferral—:info. Whether the deferred work is load-bearing is the reader's call; the shape is fragile either way.continue_to_later_sibling,continue_to_parent_supervisor,continue_crash_loop_risk—:warning. Startup races and restart loops whose outcome depends on timing rather than being guaranteed on every boot.