Skip to content

Commit 2d4dec6

Browse files
committed
Add support for experiment after_run blocks
To allow an experiment to run custom behavior based on experiment results, eg: class MyWidget include Scientist def users science "my-experiment" do |e| e.use { control_method } e.try { candidate_method } # Slower candidates need further investigation e.after_run do |result| control_duration = result.control.duration candidate_duration = result.candidates.first.duration if candidate_duration - control_duration > 15 Logger.debug("Slow experiment candidate #{context}") end end end end end
1 parent 5945f33 commit 2d4dec6

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed

lib/scientist/experiment.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,16 @@ def before_run(&block)
8787
@_scientist_before_run = block
8888
end
8989

90+
# Define a block of code to run after an experiment completes, if the experiment
91+
# is enabled.
92+
#
93+
# The block takes no arguments.
94+
#
95+
# Returns the configured block.
96+
def after_run(&block)
97+
@_scientist_after_run = block
98+
end
99+
90100
# A Hash of behavior blocks, keyed by String name. Register behavior blocks
91101
# with the `try` and `use` methods.
92102
def behaviors
@@ -230,6 +240,10 @@ def run(name = nil)
230240

231241
result = generate_result(name)
232242

243+
if @_scientist_after_run
244+
@_scientist_after_run.call(result)
245+
end
246+
233247
begin
234248
publish(result)
235249
rescue StandardError => ex

test/scientist/experiment_test.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,37 @@ def @ex.enabled?
635635
end
636636
end
637637

638+
describe "after run block" do
639+
it "runs when an experiment is enabled" do
640+
control_ok = candidate_ok = false
641+
after_result = nil
642+
@ex.after_run { |result| after_result = result }
643+
@ex.use { control_ok = after_result.nil? }
644+
@ex.try { candidate_ok = after_result.nil? }
645+
646+
@ex.run
647+
648+
assert after_result, "after_run should have run"
649+
assert after_result.matched?, "after_run should be called with the result"
650+
assert control_ok, "control should have run before after_run"
651+
assert candidate_ok, "candidate should have run before after_run"
652+
end
653+
654+
it "does not run when an experiment is disabled" do
655+
after_result = nil
656+
657+
def @ex.enabled?
658+
false
659+
end
660+
@ex.after_run { |result| after_result = result }
661+
@ex.use { "value" }
662+
@ex.try { "value" }
663+
@ex.run
664+
665+
refute after_result, "after_run should not have run"
666+
end
667+
end
668+
638669
describe "testing hooks for extending code" do
639670
it "allows a user to provide fabricated durations for testing purposes" do
640671
@ex.use { true }

0 commit comments

Comments
 (0)