Class: Cuboid::MCP::CoreTools::KillInstance
- Defined in:
- lib/cuboid/mcp/core_tools.rb
Constant Summary collapse
- REAP_GRACE_SECONDS =
Send TERM, give the engine up to ~10s to drain its browser cluster + at_exit chain (which is what unlinks per-engine temp dirs), then SIGKILL if anything’s still alive. The earlier 2s grace was generally too short for engines with an active browser pool — they’d get SIGKILL’d mid-shutdown and leak ‘/tmp/<App>Engine<…>/` directories. Daemonised processes have no parent to wait() on, so we can’t reap; we just verify exit by ESRCH on ‘kill 0`. All branches are best-effort — a missing PID, ESRCH, or EPERM are all silently ignored.
10.0
Class Method Summary collapse
Class Method Details
.call(instance_id:) ⇒ Object
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/cuboid/mcp/core_tools.rb', line 250 def self.call( instance_id:, ** ) CoreTools.instrumented_call do instance = CoreTools.instances[instance_id] raise "unknown instance: #{instance_id}" if !instance # `instance.shutdown` is an RPC call asking the engine # to clean up gracefully. The daemonised subprocess # *should* exit on its own afterwards, but in practice # it sometimes doesn't — leaking the ruby PID plus its # whole chromedriver / browser pool subtree (each # engine spawns ~7 chromes). Reap the PID directly # too: TERM, brief grace, then KILL if still around. pid = instance.pid rescue nil (instance.shutdown rescue nil) CoreTools.instances.delete( instance_id ).close # Drop any live-event registration so future engine # pushes 410 instead of being silently relayed. ::Cuboid::MCP::Live.unregister( instance_id ) if pid && pid > 0 reap_engine_pid( pid ) end { killed: instance_id } end end |
.reap_engine_pid(pid) ⇒ Object
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
# File 'lib/cuboid/mcp/core_tools.rb', line 289 def self.reap_engine_pid( pid ) Process.kill( 'TERM', pid ) rescue nil deadline = Process.clock_gettime( Process::CLOCK_MONOTONIC ) + REAP_GRACE_SECONDS while Process.clock_gettime( Process::CLOCK_MONOTONIC ) < deadline begin Process.kill( 0, pid ) sleep 0.1 rescue Errno::ESRCH return rescue Errno::EPERM return end end Process.kill( 'KILL', pid ) rescue nil end |