Class: DecisionAgent::ABTesting::ABTestManager
- Inherits:
-
Object
- Object
- DecisionAgent::ABTesting::ABTestManager
- Includes:
- MonitorMixin
- Defined in:
- lib/decision_agent/ab_testing/ab_test_manager.rb
Overview
Manages A/B tests and provides high-level orchestration
Instance Attribute Summary collapse
-
#storage_adapter ⇒ Object
readonly
Returns the value of attribute storage_adapter.
-
#version_manager ⇒ Object
readonly
Returns the value of attribute version_manager.
Instance Method Summary collapse
-
#active_tests ⇒ Array<ABTest>
Get all active A/B tests.
-
#assign_variant(test_id:, user_id: nil) ⇒ Hash
Assign a variant for a request.
-
#cancel_test(test_id) ⇒ Object
Cancel a test.
-
#complete_test(test_id) ⇒ Object
Complete a running test.
-
#create_test(name:, champion_version_id:, challenger_version_id:, traffic_split: { champion: 90, challenger: 10 }, start_date: nil, end_date: nil) ⇒ ABTest
Create a new A/B test.
-
#get_results(test_id) ⇒ Hash
Get results comparison for an A/B test.
-
#get_test(test_id) ⇒ ABTest?
Get an A/B test by ID.
-
#initialize(storage_adapter: nil, version_manager: nil) ⇒ ABTestManager
constructor
A new instance of ABTestManager.
-
#list_tests(status: nil, limit: nil) ⇒ Array<ABTest>
List all tests with optional filtering.
-
#record_decision(assignment_id:, decision:, confidence:) ⇒ Object
Record the decision result for an assignment.
-
#start_test(test_id) ⇒ Object
Start a scheduled test.
Constructor Details
#initialize(storage_adapter: nil, version_manager: nil) ⇒ ABTestManager
15 16 17 18 19 20 |
# File 'lib/decision_agent/ab_testing/ab_test_manager.rb', line 15 def initialize(storage_adapter: nil, version_manager: nil) super() @storage_adapter = storage_adapter || default_storage_adapter @version_manager = version_manager || Versioning::VersionManager.new @active_tests_cache = {} end |
Instance Attribute Details
#storage_adapter ⇒ Object (readonly)
Returns the value of attribute storage_adapter.
11 12 13 |
# File 'lib/decision_agent/ab_testing/ab_test_manager.rb', line 11 def storage_adapter @storage_adapter end |
#version_manager ⇒ Object (readonly)
Returns the value of attribute version_manager.
11 12 13 |
# File 'lib/decision_agent/ab_testing/ab_test_manager.rb', line 11 def version_manager @version_manager end |
Instance Method Details
#active_tests ⇒ Array<ABTest>
Get all active A/B tests
62 63 64 65 66 67 68 69 70 |
# File 'lib/decision_agent/ab_testing/ab_test_manager.rb', line 62 def active_tests synchronize do return @active_tests_cache[:tests] if cache_valid? tests = @storage_adapter.list_tests(status: "running") @active_tests_cache = { tests: tests, timestamp: Time.now.utc } tests end end |
#assign_variant(test_id:, user_id: nil) ⇒ Hash
Assign a variant for a request
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/decision_agent/ab_testing/ab_test_manager.rb', line 76 def assign_variant(test_id:, user_id: nil) test = get_test(test_id) raise TestNotFoundError, "Test not found: #{test_id}" unless test variant = test.assign_variant(user_id: user_id) version_id = test.version_for_variant(variant) assignment = ABTestAssignment.new( ab_test_id: test_id, user_id: user_id, variant: variant, version_id: version_id ) saved_assignment = @storage_adapter.save_assignment(assignment) { test_id: test_id, variant: variant, version_id: version_id, assignment_id: saved_assignment.id } end |
#cancel_test(test_id) ⇒ Object
Cancel a test
158 159 160 161 162 163 164 165 166 167 |
# File 'lib/decision_agent/ab_testing/ab_test_manager.rb', line 158 def cancel_test(test_id) synchronize do test = get_test(test_id) raise TestNotFoundError, "Test not found: #{test_id}" unless test test.cancel! @storage_adapter.update_test(test_id, status: "cancelled") invalidate_cache! end end |
#complete_test(test_id) ⇒ Object
Complete a running test
145 146 147 148 149 150 151 152 153 154 |
# File 'lib/decision_agent/ab_testing/ab_test_manager.rb', line 145 def complete_test(test_id) synchronize do test = get_test(test_id) raise TestNotFoundError, "Test not found: #{test_id}" unless test test.complete! @storage_adapter.update_test(test_id, status: "completed", end_date: test.end_date) invalidate_cache! end end |
#create_test(name:, champion_version_id:, challenger_version_id:, traffic_split: { champion: 90, challenger: 10 }, start_date: nil, end_date: nil) ⇒ ABTest
Create a new A/B test
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/decision_agent/ab_testing/ab_test_manager.rb', line 30 def create_test(name:, champion_version_id:, challenger_version_id:, traffic_split: { champion: 90, challenger: 10 }, start_date: nil, end_date: nil) synchronize do # Validate that both versions exist validate_version_exists!(champion_version_id, "champion") validate_version_exists!(challenger_version_id, "challenger") test = ABTest.new( name: name, champion_version_id: champion_version_id, challenger_version_id: challenger_version_id, traffic_split: traffic_split, start_date: start_date || Time.now.utc, end_date: end_date, status: start_date && start_date > Time.now.utc ? "scheduled" : "running" ) saved_test = @storage_adapter.save_test(test) invalidate_cache! saved_test end end |
#get_results(test_id) ⇒ Hash
Get results comparison for an A/B test
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/decision_agent/ab_testing/ab_test_manager.rb', line 111 def get_results(test_id) test = get_test(test_id) raise TestNotFoundError, "Test not found: #{test_id}" unless test assignments = @storage_adapter.get_assignments(test_id) champion_assignments = assignments.select { |a| a.variant == :champion } challenger_assignments = assignments.select { |a| a.variant == :challenger } { test: test.to_h, champion: calculate_variant_stats(champion_assignments, "Champion"), challenger: calculate_variant_stats(challenger_assignments, "Challenger"), comparison: compare_variants(champion_assignments, challenger_assignments), total_assignments: assignments.size, timestamp: Time.now.utc } end |
#get_test(test_id) ⇒ ABTest?
Get an A/B test by ID
56 57 58 |
# File 'lib/decision_agent/ab_testing/ab_test_manager.rb', line 56 def get_test(test_id) @storage_adapter.get_test(test_id) end |
#list_tests(status: nil, limit: nil) ⇒ Array<ABTest>
List all tests with optional filtering
173 174 175 |
# File 'lib/decision_agent/ab_testing/ab_test_manager.rb', line 173 def list_tests(status: nil, limit: nil) @storage_adapter.list_tests(status: status, limit: limit) end |
#record_decision(assignment_id:, decision:, confidence:) ⇒ Object
Record the decision result for an assignment
104 105 106 |
# File 'lib/decision_agent/ab_testing/ab_test_manager.rb', line 104 def record_decision(assignment_id:, decision:, confidence:) @storage_adapter.update_assignment(assignment_id, decision_result: decision, confidence: confidence) end |
#start_test(test_id) ⇒ Object
Start a scheduled test
132 133 134 135 136 137 138 139 140 141 |
# File 'lib/decision_agent/ab_testing/ab_test_manager.rb', line 132 def start_test(test_id) synchronize do test = get_test(test_id) raise TestNotFoundError, "Test not found: #{test_id}" unless test test.start! @storage_adapter.update_test(test_id, status: "running", start_date: test.start_date) invalidate_cache! end end |