Skip to content
Ahmed Abbas edited this page Jun 8, 2026 · 2 revisions

Convert Ruby SDK

The Convert Ruby SDK brings A/B testing, feature flags, and personalization to server-side Ruby applications. It resolves experiment and feature decisions in-process from a cached bucketing config, then queues, batches, and flushes tracking events in the background — surviving process forks (Puma cluster, Unicorn, Passenger) with zero configuration.

Source Repository: ruby-sdk · Gem: convert_sdk (RubyGems) · Ruby: 3.1+ (CRuby + JRuby)

flowchart TD
    A0["ConvertSdk.create / Client"]
    A1["Context"]
    A2["DataManager (decision flow)"]
    A3["RuleManager / Comparisons"]
    A4["BucketingManager"]
    A5["ApiManager / VisitorsQueue"]
    A6["FeatureManager"]
    A7["SegmentsManager"]
    A8["EventManager"]
    A9["DataStoreManager (MemoryStore / RedisStore)"]
    A10["BackgroundTimer (refresh + flush)"]
    A11["ForkGuard (Process._fork)"]
    A0 -- "Creates" --> A1
    A0 -- "Fetches config via" --> A2
    A0 -- "Wires queue" --> A5
    A0 -- "Fires events via" --> A8
    A1 -- "Runs experiences via" --> A2
    A1 -- "Runs features via" --> A6
    A1 -- "Custom segments via" --> A7
    A1 -- "Enqueues tracking via" --> A5
    A2 -- "Gates with" --> A3
    A2 -- "Buckets via" --> A4
    A2 -- "Persists sticky state via" --> A9
    A5 -- "Delivers via HTTP, drains via" --> A10
    A10 -- "Registered with" --> A11
Loading

Key Differences from the JavaScript SDK

The Ruby SDK shares the same architecture and bucketing algorithm as the JavaScript SDK, so variation assignment is deterministic and identical across SDKs. It is adapted for the server-side Ruby runtime:

  • Module factory, not constructorConvertSdk.create(sdk_key: "...") (or data: for direct-data mode) replaces new ConvertSDK(...). It fetches and installs config synchronously and fires the ready lifecycle event.
  • Zero runtime dependencies — stdlib only (Net::HTTP, JSON, Mutex). The optional redis gem is required lazily only when you use the RedisStore.
  • Fork-safe by construction — background threads start lazily on first use (never in the factory), an automatic Process._fork hook re-arms every forked worker, PID guards cover Process.daemon, and a PID-guarded at_exit flushes only in the registering process. A Puma cluster with preload_app! needs no fork-handling code.
  • Sentinel returns, never exceptions — misses return frozen sentinels (RuleError::NO_DATA_FOUND, RuleError::NEED_MORE_DATA, BucketingError::VARIATION_NOT_DECIDED) with a nil #key; the integrator pattern is case variation&.key. No decision method ever raises into the host.
  • Two-worlds naming — the public API is snake_case (run_experience, track_conversion, force_multiple_transactions:); the wire payload is camelCase (visitorId, goalData), translated only at the inbound (Config) and outbound (ApiManager) boundaries.
  • Typed — ships RBS signatures validated by rbs validate + steep check; runs on CRuby 3.1–3.4 and JRuby.

Getting Started

Ruby SDK

Core Concepts

How-To Guides

Contributing

Clone this wiki locally