Class: Cuboid::RPC::Server::Instance
- Includes:
- UI::Output, Utilities
- Defined in:
- lib/cuboid/rpc/server/instance.rb,
lib/cuboid/rpc/server/instance/peers.rb,
lib/cuboid/rpc/server/instance/service.rb
Overview
Defined Under Namespace
Modules: Service Classes: Peers
Constant Summary collapse
- SHUTDOWN_GRACE_SECONDS =
Makes the server go bye-bye…Lights out!
‘shutdown` must reliably take the Ruby process with it. Stopping the reactor + RPC server alone leaves the Application’s non-daemon threads (audit workers, browser cluster manager, etc.) blocking the runtime — historically this leaked engine subprocesses every time ‘kill_instance` was called over MCP, and showed up in the cuboid spec suite as leftover ruby processes after the run. The `instance.shutdown` RPC returned success but the daemonised process never actually exited.
Two-stage exit:
1. Raise SystemExit on the **main thread** so the at_exit chain runs (Cuboid_<pid> tmpdir cleanup, live-plugin's `exited` push). SystemExit raised on a non-main thread only kills that thread — must hit the main one. 2. Watchdog SIGKILL after a grace window in case a non-daemon Application thread refuses to release. The Paths boot-sweep reaps the orphaned tmpdir on the next cuboid process launch even when at_exit didn't run. 5.0
Class Method Summary collapse
Instance Method Summary collapse
-
#abort_and_generate_report ⇒ Hash
Cleans up and returns the report.
-
#agent_url ⇒ String?
Agent URL that provided this Instance, ‘nil` if not provided by a Agent.
- #alive? ⇒ true
- #application ⇒ Object
-
#busy? ⇒ Bool
‘true` if the scan is initializing or running, `false` otherwise.
- #consumed_pids ⇒ Object
- #error_test(str) ⇒ Object
- #errors(starting_line = 0) ⇒ Object
- #generate_report ⇒ Hash
-
#initialize(options, token) ⇒ Instance
constructor
Initializes the RPC interface and the framework.
-
#progress(options = {}) ⇒ Hash
# Recommended usage.
- #restore!(snapshot) ⇒ Object
-
#run(options = nil) ⇒ Object
Configures and runs a job.
-
#scheduler_url ⇒ String?
Scheduler URL to which this Instance is attached, ‘nil` if not attached.
- #shutdown(&block) ⇒ Object
Methods included from Utilities
#available_port, available_port_mutex, #bytes_to_kilobytes, #bytes_to_megabytes, #caller_name, #caller_path, #exception_jail, #generate_token, #hms_to_seconds, #port_available?, #rand_port, #random_seed, #regexp_array_match, #remove_constants, #seconds_to_hms
Methods included from UI::Output
#error_buffer, initialize, #log_error, #output_provider_file, #print_bad, #print_debug, #print_error, #print_info, #print_line, #print_ok, #print_status, #print_verbose, #reroute_to_file, #reroute_to_file?
Methods included from UI::OutputInterface
Methods included from UI::OutputInterface::Personalization
Methods included from UI::OutputInterface::Controls
#debug?, #debug_level, #debug_level_1?, #debug_level_2?, #debug_level_3?, #debug_level_4?, #debug_off, #debug_on, initialize, #verbose?, #verbose_off, #verbose_on
Methods included from UI::OutputInterface::ErrorLogging
#error_logfile, #has_error_log?, initialize, #set_error_logfile
Methods included from UI::OutputInterface::Implemented
#print_debug_backtrace, #print_debug_exception, #print_debug_level_1, #print_debug_level_2, #print_debug_level_3, #print_debug_level_4, #print_error_backtrace, #print_exception
Methods included from UI::OutputInterface::Abstract
#output_provider_file, #print_bad, #print_debug, #print_error, #print_info, #print_line, #print_ok, #print_status, #print_verbose
Constructor Details
#initialize(options, token) ⇒ Instance
Initializes the RPC interface and the framework.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/cuboid/rpc/server/instance.rb', line 45 def initialize( , token ) @options = @token = token @application = Server::ApplicationWrapper.new( Cuboid::Application.application ) @active_options = Server::ActiveOptions.new @server = Base.new( @options.rpc., token ) if @options.datastore.log_level @server.logger.level = @options.datastore.log_level end @options.datastore.token = token if @options.output.reroute_to_logfile reroute_to_file "#{@options.paths.logs}Instance-#{Process.pid}-#{@options.rpc.server_port}.log" else reroute_to_file false end set_error_logfile "#{@options.paths.logs}Instance-#{Process.pid}-#{@options.rpc.server_port}.error.log" set_handlers( @server ) # trap interrupts and exit cleanly when required %w(QUIT INT).each do |signal| next if !Signal.list.has_key?( signal ) trap( signal ){ shutdown if !@options.datastore.do_not_trap } end @raktr = Raktr.new @raktr.run do _run end end |
Class Method Details
.parse_progress_opts(options, key) ⇒ Object
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
# File 'lib/cuboid/rpc/server/instance.rb', line 297 def self.parse_progress_opts( , key ) parsed = {} [.delete( key ) || .delete( key.to_s )].compact.each do |w| case w when Array w.compact.flatten.each do |q| case q when String, Symbol parsed[q.to_sym] = nil when Hash parsed.merge!( q.my_symbolize_keys ) end end when String, Symbol parsed[w.to_sym] = nil when Hash parsed.merge!( w.my_symbolize_keys ) end end parsed end |
Instance Method Details
#abort_and_generate_report ⇒ Hash
Cleans up and returns the report.
137 138 139 140 |
# File 'lib/cuboid/rpc/server/instance.rb', line 137 def abort_and_generate_report @application.abort! generate_report end |
#agent_url ⇒ String?
Returns Agent URL that provided this Instance, ‘nil` if not provided by a Agent.
97 98 99 |
# File 'lib/cuboid/rpc/server/instance.rb', line 97 def agent_url @options.agent.url end |
#alive? ⇒ true
122 123 124 |
# File 'lib/cuboid/rpc/server/instance.rb', line 122 def alive? @server.alive? end |
#application ⇒ Object
84 85 86 |
# File 'lib/cuboid/rpc/server/instance.rb', line 84 def application Application.application.to_s end |
#busy? ⇒ Bool
Returns ‘true` if the scan is initializing or running, `false` otherwise.
128 129 130 |
# File 'lib/cuboid/rpc/server/instance.rb', line 128 def busy? @run_initializing || @application.busy? end |
#consumed_pids ⇒ Object
293 294 295 |
# File 'lib/cuboid/rpc/server/instance.rb', line 293 def consumed_pids [Process.pid] end |
#error_test(str) ⇒ Object
288 289 290 |
# File 'lib/cuboid/rpc/server/instance.rb', line 288 def error_test( str ) @application.error_test( str ) end |
#errors(starting_line = 0) ⇒ Object
283 284 285 |
# File 'lib/cuboid/rpc/server/instance.rb', line 283 def errors( starting_line = 0 ) @application.errors( starting_line ) end |
#generate_report ⇒ Hash
Returns Cuboid::Report#to_rpc_data.
144 145 146 |
# File 'lib/cuboid/rpc/server/instance.rb', line 144 def generate_report @application.generate_report.to_rpc_data end |
#progress(options = {}) ⇒ Hash
# Recommended usage
Please request from the method only the things you are going to actually
use, otherwise you'll just be wasting bandwidth.
In addition, ask to **not** be served data you already have, like
error messages.
To be kept completely up to date on the progress of a scan (i.e. receive
new issues and error messages asap) in an efficient manner, you will need
to keep track of the error messages you already have and explicitly tell
the method to not send the same data back to you on subsequent calls.
## Retrieving errors (‘:errors` option) without duplicate data
This is done by telling the method how many error messages you already
have and you will be served the errors from the error-log that are past
that line.
So, if you were to use a loop to get fresh progress data it would look
like so:
error_cnt = 0
i = 0
while sleep 1
# Test method, triggers an error log...
instance.error_test "BOOM! #{i+=1}"
# Only request errors we don't already have
errors = instance.progress( with: { errors: error_cnt } )[:errors]
error_cnt += errors.size
# You will only see new errors
puts errors.join("\n")
end
200 201 202 |
# File 'lib/cuboid/rpc/server/instance.rb', line 200 def progress( = {} ) progress_handler( .merge( as_hash: true ) ) end |
#restore!(snapshot) ⇒ Object
106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/cuboid/rpc/server/instance.rb', line 106 def restore!( snapshot ) # If the instance isn't clean bail out now. return false if busy? || @called @called = @run_initializing = true Thread.new do @application.restore!( snapshot ) @application.run @run_initializing = false end true end |
#run(options = nil) ⇒ Object
Configures and runs a job.
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/cuboid/rpc/server/instance.rb', line 205 def run( = nil ) # If the instance isn't clean bail out now. return false if busy? || @called if !@application.( ) fail ArgumentError, 'Invalid options!' end # There may be follow-up/retry calls by the client in cases of network # errors (after the request has reached us) so we need to keep minimal # track of state in order to bail out on subsequent calls. @called = @run_initializing = true @active_options.set( application: ) Thread.new do @application.run @run_initializing = false end true end |
#scheduler_url ⇒ String?
Returns Scheduler URL to which this Instance is attached, ‘nil` if not attached.
90 91 92 |
# File 'lib/cuboid/rpc/server/instance.rb', line 90 def scheduler_url @options.scheduler.url end |
#shutdown(&block) ⇒ 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 276 277 278 279 280 281 |
# File 'lib/cuboid/rpc/server/instance.rb', line 250 def shutdown( &block ) if @shutdown block.call if block_given? return end @shutdown = true print_status 'Shutting down...' @application.shutdown # We're shutting down services so we need to use a concurrent way but # without going through the Reactor. Thread.new do @server.shutdown @raktr.stop block.call true if block_given? # Stage 1 — graceful: SystemExit on the main thread so # at_exit handlers run. main = Thread.main if main && main.alive? && main != Thread.current main.raise( SystemExit.new( 0 ) ) rescue nil end # Stage 2 — watchdog: hammer if main can't unwind. sleep SHUTDOWN_GRACE_SECONDS Process.kill( 'KILL', Process.pid ) rescue nil end true end |