agentic examples

Tenant Shards

Tenant Shards: at scale, "the plan" becomes "the plan, per shard" - same pipeline, isolated blast radius. Each shard gets its own journal (its own recovery story) and its own rate limit (its own noisy neighbor containment), under one control plane. Shard 2 crashes mid-run; the rerun resumes ONLY what shard 2 didn't finish, because recovery, like everything at scale, must be per-shard.

Reliability & Recovery Round 11 Eileen Uchitelle exit 0

source on github

bundle exec ruby examples/tenant_shards.rb

a real captured run

TENANT SHARDS (3 shards, 6 tenants, pipeline: extract -> transform -> load)

  run 1 - shard_2 loses power mid-tenant:
    shard_1   completed         6 steps ran
    shard_2   partial_failure   7 steps ran  <- crashed at umbrella:transform
    shard_3   completed         3 steps ran

  run 2 - control plane reruns everything; journals decide what that means:
    shard_1   completed         0 steps ran,  6 skipped (already journaled)
    shard_2   completed         2 steps ran,  7 skipped (already journaled)
    shard_3   completed         0 steps ran,  3 skipped (already journaled)

  the rerun was issued fleet-wide - the control plane doesn't
  track which shard crashed, and shouldn't have to. shard 1 and 3
  skipped everything (their journals proved completion); shard 2
  re-ran only from the crash point. that's the sharding contract:
  one plan definition, N isolated executions, N recovery stories,
  N rate limits - and a blast radius that ends at the shard
  boundary. scale isn't a bigger machine; it's smaller failures.

source

# frozen_string_literal: true

# Tenant Shards: at scale, "the plan" becomes "the plan, per shard" -
# same pipeline, isolated blast radius. Each shard gets its own
# journal (its own recovery story) and its own rate limit (its own
# noisy neighbor containment), under one control plane. Shard 2
# crashes mid-run; the rerun resumes ONLY what shard 2 didn't finish,
# because recovery, like everything at scale, must be per-shard.
#
#   bundle exec ruby examples/tenant_shards.rb
#
# Runs offline; the crash is scripted, the resume is real.

require class="s">"bundler/setup"
require class="s">"agentic"
require class="s">"tmpdir"

Agentic.logger.level = class="y">:fatal

SHARDS = {
  class="s">"shard_1" => %w[acme globex],
  class="s">"shard_2" => %w[initech umbrella hooli],
  class="s">"shard_3" => %w[wonka]
}.freeze
PIPELINE = %w[extract transform load].freeze

def journal_path(shard) = File.join(Dir.tmpdir, class="s">"agentic_#{shard}.journal.jsonl")

# One shard's run: its own journal, its own limiter, resume-aware
def run_shard(shard, tenants, crash_at: nil)
  journal = Agentic:class="y">:ExecutionJournal.new(path: journal_path(shard))
  done = Agentic:class="y">:ExecutionJournal.replay(path: journal_path(shard))
  limiter = Agentic:class="y">:RateLimit.new(2) # per-shard: a hot shard can't starve the others

  orchestrator = Agentic:class="y">:PlanOrchestrator.new(
    concurrency_limit: 2, lifecycle_hooks: journal.lifecycle_hooks,
    retry_policy: {max_retries: 0, retryable_errors: []}
  )
  ran = 0
  skipped = 0
  tenants.each do |tenant|
    previous = nil
    PIPELINE.each do |step|
      name = class="s">"#{tenant}:#{step}"
      if done.completed?(name)
        skipped += 1
        next
      end

      task = Agentic:class="y">:Task.new(description: name, agent_spec: {class="s">"name" => name, class="s">"instructions" => class="s">"run"})
      orchestrator.add_task(task, previous ? [previous] : [], agent: ->(t) {
        raise class="s">"power cut" if crash_at == t.description

        limiter.acquire { sleep(0.002) }
        ran += 1
        class="y">:ok
      })
      previous = task
    end
  end
  status = orchestrator.execute_plan.status
  [status, ran, skipped]
end

puts class="s">"TENANT SHARDS (#{SHARDS.size} shards, #{SHARDS.values.sum(&class="y">:size)} tenants, pipeline: #{PIPELINE.join(" -> class="s">")})"
puts
SHARDS.each_key { |shard| File.delete(journal_path(shard)) if File.exist?(journal_path(shard)) }

puts class="s">"  run 1 - shard_2 loses power mid-tenant:"
SHARDS.each do |shard, tenants|
  crash = (shard == class="s">"shard_2") ? class="s">"umbrella:transform" : nil
  status, ran, = run_shard(shard, tenants, crash_at: crash)
  puts format(class="s">"    %-9s %-16s %2d steps ran%s", shard, status, ran,
    crash ? class="s">"  <- crashed at #{crash}" : class="s">"")
end
puts

puts class="s">"  run 2 - control plane reruns everything; journals decide what that means:"
SHARDS.each do |shard, tenants|
  status, ran, skipped = run_shard(shard, tenants)
  puts format(class="s">"    %-9s %-16s %2d steps ran, %2d skipped (already journaled)", shard, status, ran, skipped)
end
puts
puts class="s">"  the rerun was issued fleet-wide - the control plane doesn't"
puts class="s">"  track which shard crashed, and shouldn't have to. shard 1 and 3"
puts class="s">"  skipped everything (their journals proved completion); shard 2"
puts class="s">"  re-ran only from the crash point. that's the sharding contract:"
puts class="s">"  one plan definition, N isolated executions, N recovery stories,"
puts class="s">"  N rate limits - and a blast radius that ends at the shard"
puts class="s">"  boundary. scale isn't a bigger machine; it's smaller failures."