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` (default) — load into the main space and call directly. Lowest cost; no isolation. Fine for the common case 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` — 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.



67
68
69
70
71
72
73
# File 'lib/rigor/plugin/isolation.rb', line 67

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.



57
58
59
# File 'lib/rigor/plugin/isolation.rb', line 57

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.



46
47
48
49
# File 'lib/rigor/plugin/isolation.rb', line 46

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