From 7c632c1560bf963a3c9585117923e3d7fc5d6375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Luis=20Leal=20Cardoso=20Junior?= Date: Sun, 19 Jul 2026 17:17:02 -0300 Subject: [PATCH] Prefetch trial state in one pipelined roundtrip --- lib/split/experiment.rb | 48 +++++++++++++++++++++++++++++------------ lib/split/trial.rb | 2 ++ 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/lib/split/experiment.rb b/lib/split/experiment.rb index f9854587..3820a0cc 100644 --- a/lib/split/experiment.rb +++ b/lib/split/experiment.rb @@ -176,19 +176,29 @@ def start end def start_time - @start_time ||= Split.cache(:experiment_start_times, @name) do - t = redis.hget(:experiment_start_times, @name) - if t - # Check if stored time is an integer - if t =~ /^[-+]?[0-9]+$/ - Time.at(t.to_i) - else - Time.parse(t) - end - end + return @start_time if defined?(@start_time) + + @start_time = Split.cache(:experiment_start_times, @name) do + parse_start_time(redis.hget(:experiment_start_times, @name)) end end + def prefetch_trial_state! + winner_name, raw_start_time, raw_version, raw_cohorting = + redis.pipelined do |pipe| + pipe.hget(:experiment_winner, name) + pipe.hget(:experiment_start_times, @name) + pipe.get("#{name}:version") + pipe.hget(experiment_config_key, :cohorting) + end + + @has_winner = !winner_name.nil? + @start_time = parse_start_time(raw_start_time) + @version = raw_version.to_i + @cohorting_disabled = raw_cohorting.nil? ? false : raw_cohorting.downcase == "true" + self + end + def next_alternative winner || random_alternative end @@ -402,10 +412,9 @@ def jstring(goal = nil) end def cohorting_disabled? - @cohorting_disabled ||= begin - value = redis.hget(experiment_config_key, :cohorting) - value.nil? ? false : value.downcase == "true" - end + return @cohorting_disabled if defined?(@cohorting_disabled) + value = redis.hget(experiment_config_key, :cohorting) + @cohorting_disabled = value.nil? ? false : value.downcase == "true" end def disable_cohorting @@ -424,6 +433,17 @@ def experiment_config_key end private + def parse_start_time(t) + return if t.nil? + + # Check if stored time is an integer + if t =~ /^[-+]?[0-9]+$/ + Time.at(t.to_i) + else + Time.parse(t) + end + end + def redis Split.redis end diff --git a/lib/split/trial.rb b/lib/split/trial.rb index cf858b31..4cf8930a 100644 --- a/lib/split/trial.rb +++ b/lib/split/trial.rb @@ -56,6 +56,8 @@ def choose!(context = nil) # Only run the process once return alternative if @alternative_chosen + @experiment.prefetch_trial_state! + new_participant = @user[@experiment.key].nil? if override_is_alternative? self.alternative = @options[:override]