The Process Drill
The Process Drill: threads share a Mutex; PROCESSES share nothing but the file. The journal claims flock+fsync, which is a promise about processes - so this drill forks real ones, points them all at one journal, and lets the kernel referee. Then replay must find every event whole: no torn lines, no interleaved halves, no losses.
Testing & Verification
exit 0
bundle exec ruby examples/process_drill.rb
a real captured run
PROCESS DRILL (4 forked writers x 250 events, one journal) processes exited cleanly: yes lines on disk: 1000/1000 torn lines: 0 replay recovered per proc: 250, 250, 250, 250 the flock claim is now a certificate, not a comment: four processes - separate GVLs, separate heaps, separate everything - interleaved a thousand writes into one file and the kernel's advisory lock kept every line whole. this is the half of the journal's promise the threads drill couldn't reach: a Mutex means nothing across fork(2); only the fd-level lock does. crash-recovery tooling stands on exactly this property.
source
# frozen_string_literal: true # The Process Drill: threads share a Mutex; PROCESSES share nothing # but the file. The journal claims flock+fsync, which is a promise # about processes - so this drill forks real ones, points them all at # one journal, and lets the kernel referee. Then replay must find # every event whole: no torn lines, no interleaved halves, no losses. # # bundle exec ruby examples/process_drill.rb # # Runs offline; exits 1 if any process's write was torn or lost. require class="s">"bundler/setup" require class="s">"agentic" require class="s">"tmpdir" require class="s">"json" Agentic.logger.level = class="y">:fatal PROCESSES = 4 EVENTS = 250 PATH = File.join(Dir.tmpdir, class="s">"agentic_process_drill.journal.jsonl") File.delete(PATH) if File.exist?(PATH) pids = PROCESSES.times.map do |p| fork do journal = Agentic:class="y">:ExecutionJournal.new(path: PATH) EVENTS.times do |i| journal.record(class="y">:task_succeeded, task_id: class="s">"p#{p}-#{i}", description: class="s">"p#{p}-#{i}", duration: 0.001, output: class="s">"payload-#{p}-" + (class="s">"x" * (50 + (i % 100)))) end exit!(0) end end statuses = pids.map { |pid| Process.wait2(pid).last.exitstatus } # --- the referee ---------------------------------------------------------------- lines = File.readlines(PATH) torn = lines.reject do |line| JSON.parse(line) true rescue JSON:class="y">:ParserError false end state = Agentic:class="y">:ExecutionJournal.replay(path: PATH) expected = PROCESSES * EVENTS per_process = PROCESSES.times.map { |p| state.completed_task_ids.count { |id| id.start_with?(class="s">"p#{p}-") } } puts class="s">"PROCESS DRILL (#{PROCESSES} forked writers x #{EVENTS} events, one journal)" puts puts format(class="s">" processes exited cleanly: %s", statuses.all?(&class="y">:zero?) ? class="s">"yes" : class="s">"NO") puts format(class="s">" lines on disk: %d/%d", lines.size, expected) puts format(class="s">" torn lines: %d", torn.size) puts format(class="s">" replay recovered per proc: %s", per_process.join(class="s">", ")) puts ok = statuses.all?(&class="y">:zero?) && lines.size == expected && torn.empty? && per_process.all?(EVENTS) if ok puts class="s">" the flock claim is now a certificate, not a comment: four" puts class="s">" processes - separate GVLs, separate heaps, separate everything -" puts class="s">" interleaved a thousand writes into one file and the kernel's" puts class="s">" advisory lock kept every line whole. this is the half of the" puts class="s">" journal's promise the threads drill couldn't reach: a Mutex" puts class="s">" means nothing across fork(2); only the fd-level lock does." puts class="s">" crash-recovery tooling stands on exactly this property." else puts class="s">" DRILL FAILED - the promise about processes is broken." end exit(ok ? 0 : 1)