Module: Rigor::Plugin::Isolation

Defined in:
lib/rigor/plugin/isolation.rb

Overview

ADR-39 slice 5 — the selectable isolation strategy for target-library invocation. A plugin invokes a pure method on a trusted target library (e.g. ActiveSupport::Inflector.pluralize("post")) through Isolation.call; how much the invocation is isolated from Rigor's own process is a configurable strategy (RIGOR_PLUGIN_ISOLATION env; the exe/rigor launcher maps .rigor.yml's plugins_isolation: onto it before re-exec). Three backends behind one interface:

  • none — load into the main space and call directly. Lowest cost; no isolation. Used as the fallback where fork is unavailable; fine because the invoked library is trusted + pure.
  • ruby_box — call inside a Box (Ruby::Box, RUBY_BOX=1). Isolates core-class monkey-patches + lets gem versions coexist, but a native crash in the boxed work still takes the process down (in-process).
  • process (default) — call in a forked worker (Process); returns data over a pipe. The strongest: a child crash (even SIGSEGV) is contained — the parent survives and declines. Higher cost (fork + IPC).

All three answer with the method's return value, or raise Unavailable (never approximate) when the target library cannot be reached in the chosen strategy — the caller's per-plugin rescue turns that into silence, never a wrong fact.

Defined Under Namespace

Modules: Direct, Process, RubyBox Classes: Unavailable

Constant Summary collapse

STRATEGIES =
%w[none ruby_box process].freeze
DEFAULT =

The default strategy. process (a crash-contained forked worker) is the default: it isolates the target library's monkey-patches + crashes from Rigor with no in-process contamination, and forks a single persistent worker (not one per call). It falls back to none where fork is unavailable (see #backend).

"process"

Class Method Summary collapse

Class Method Details

.backendObject

The backend module for the configured strategy. process (including the default) falls back to Direct where fork is unavailable (Windows / JRuby) so inflection still works rather than silently degrading — the libraries are trusted + pure, so the main-space fallback is acceptable when no fork-based isolation can be had.



58
59
60
61
62
63
64
# File 'lib/rigor/plugin/isolation.rb', line 58

def backend
  case strategy_name
  when "ruby_box" then RubyBox
  when "none" then Direct
  else Process.available? ? Process : Direct
  end
end

.call(feature:, receiver:, method:, args:) ⇒ Object

Invokes receiver.method(*args) on a target library, requiring feature first, under the configured isolation strategy. receiver is a constant name (String), method a Symbol from the caller's allow-list, and args simple, Marshal-able / inspectable values (Strings) — never free input. Returns the result, or raises Unavailable.



50
51
52
# File 'lib/rigor/plugin/isolation.rb', line 50

def call(feature:, receiver:, method:, args:)
  backend.call(feature: feature, receiver: receiver, method: method, args: args)
end

.strategy_nameObject

The configured strategy name (RIGOR_PLUGIN_ISOLATION), defaulting to DEFAULT for any unset / unrecognised value.



41
42
43
44
# File 'lib/rigor/plugin/isolation.rb', line 41

def strategy_name
  name = ENV["RIGOR_PLUGIN_ISOLATION"].to_s
  STRATEGIES.include?(name) ? name : DEFAULT
end