Class: Wurk::Swarm::ChildBoot

Inherits:
Object
  • Object
show all
Includes:
Component
Defined in:
lib/wurk/swarm/child_boot.rb

Overview

Step 5 of the boot ordering. Runs inside each forked child:

* reset signal traps inherited from the parent,
* reconnect ActiveRecord (if loaded) + open a fresh Redis pool,
* apply the slot's queues + concurrency to the default capsule,
* install child signal handlers (TERM/INT drain, TSTP quiet,
USR2 reopen logs),
* launch the Wurk::Launcher and block until shutdown.

Kept separate from Wurk::Swarm so the parent supervisor stays focused on PID supervision (SRP).

Constant Summary collapse

CHILD_SIGNALS =
{ 'TERM' => :term, 'INT' => :term, 'TSTP' => :tstp, 'USR2' => :usr2 }.freeze

Constants included from Component

Component::DEFAULT_THREAD_PRIORITY, Component::LEADER_CACHE_TTL_MS, Component::PROCESS_NONCE

Instance Attribute Summary

Attributes included from Component

#config

Instance Method Summary collapse

Methods included from Component

#default_tag, #fire_event, #handle_exception, #hostname, #identity, #leader?, #logger, #mono_ms, #process_nonce, #real_ms, #redis, #safe_thread, #tid, #watchdog

Constructor Details

#initialize(config, slot, index, parent_pid: ::Process.ppid, start_quiet: false) ⇒ ChildBoot

parent_pid is captured by the swarm before it forks (race-free) and threaded through so OrphanGuard can tell "still supervised" from "reparented after the supervisor died". Defaults to the live parent for the non-swarm callers (tests) that construct a ChildBoot directly. start_quiet: — the swarm was TSTP-quieted before this child was forked (respawn/recycle during maintenance); boot the launcher already quieted so the replacement doesn't resume fetching. Delivered as a constructor flag, not a post-fork TSTP, because the signal would race the trap-reset window (default TSTP disposition suspends the child).



35
36
37
38
39
40
41
42
43
# File 'lib/wurk/swarm/child_boot.rb', line 35

def initialize(config, slot, index, parent_pid: ::Process.ppid, start_quiet: false)
  @config = config
  @slot = slot
  @index = index
  @parent_pid = parent_pid
  @start_quiet = start_quiet
  @signal_read = nil
  @signal_write = nil
end

Instance Method Details

#runObject



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/wurk/swarm/child_boot.rb', line 45

def run
  reset_inherited_signals
  reconnect_after_fork
  Wurk.server = true
  # :fork runs in each child after our internal AR/Redis reconnect and
  # before fetching, so apps can reopen sockets / restart threads /
  # reconnect non-fork-safe libs (Ent §7.4). It never fires in the parent
  # (which only forks + supervises). Like :startup, the child's forked
  # copy of the bucket is cleared after dispatch, so siblings fire theirs.
  fire_event(:fork)
  apply_slot_to_config
  # :startup must fire in each worker child before its managers spin up
  # (Sidekiq contract, reraise: true). The parent supervisor never runs
  # jobs, so the non-swarm CLI path fires it once per process — for the
  # swarm, each child fires it here. Its own forked copy of the bucket is
  # cleared after, so siblings still fire their own.
  fire_event(:startup, reraise: true)
  run_launcher
  exit 0
rescue StandardError, ::Wurk::Shutdown => e
  @config.logger.error { "swarm child ##{@index} (#{::Process.pid}) crashed: #{e.class}: #{e.message}" }
  exit 1
end