16
16
# limitations under the License.
17
17
#
18
18
module Optimizely
19
- # Default constants for CMAB requests
19
+ # Default constants for CMAB requests
20
20
DEFAULT_MAX_RETRIES = 3
21
- DEFAULT_INITIAL_BACKOFF = 0.1 # in seconds (100 ms)
22
- DEFAULT_MAX_BACKOFF = 10 # in seconds
21
+ DEFAULT_INITIAL_BACKOFF = 0.1 # in seconds (100 ms)
22
+ DEFAULT_MAX_BACKOFF = 10 # in seconds
23
23
DEFAULT_BACKOFF_MULTIPLIER = 2.0
24
24
MAX_WAIT_TIME = 10.0
25
25
@@ -39,7 +39,7 @@ class DefaultCmabClient
39
39
# Client for interacting with the CMAB service.
40
40
# Provides methods to fetch decisions with optional retry logic.
41
41
42
- def initialize ( http_client = nil , retry_config = nil , logger = nil )
42
+ def initialize ( http_client = nil , retry_config = nil , logger = nil )
43
43
# Initialize the CMAB client.
44
44
# Args:
45
45
# http_client: HTTP client for making requests.
@@ -61,110 +61,108 @@ def fetch_decision(rule_id, user_id, attributes, cmab_uuid, timeout: MAX_WAIT_TI
61
61
# Returns:
62
62
# The variation ID.
63
63
url = "https://prediction.cmab.optimizely.com/predict/#{ rule_id } "
64
- cmab_attributes = attributes . map { |key , value | { id : key , value : value } }
64
+ cmab_attributes = attributes . map { |key , value | { id : key , value : value } }
65
65
66
66
request_body = {
67
67
instances : [ {
68
- visitorId : user_id ,
69
- experimentId : rule_id ,
70
- attributes : cmab_attributes ,
71
- cmabUUID : cmab_uuid ,
68
+ visitorId : user_id ,
69
+ experimentId : rule_id ,
70
+ attributes : cmab_attributes ,
71
+ cmabUUID : cmab_uuid
72
72
} ]
73
73
}
74
74
75
- if @retry_config
76
- variation_id = _do_fetch_with_retry ( url , request_body , @retry_config , timeout )
75
+ variation_id = if @retry_config
76
+ _do_fetch_with_retry ( url , request_body , @retry_config , timeout )
77
77
else
78
- variation_id = _do_fetch ( url , request_body , timeout )
78
+ _do_fetch ( url , request_body , timeout )
79
79
end
80
80
return variation_id
81
81
end
82
82
83
83
def _do_fetch ( url , request_body , timeout )
84
- # Perform a single fetch request to the CMAB prediction service.
85
-
86
- # Args:
87
- # url: The endpoint URL.
88
- # request_body: The request payload.
89
- # timeout: Maximum wait time for the request to respond in seconds.
90
- # Returns:
91
- # The variation ID from the response.
92
-
93
- headers = { 'Content-Type' => 'application/json' }
94
- begin
95
- response = @http_client . post ( url , json : request_body , headers : headers , timeout : timeout )
96
- rescue StandardError => e
97
- error_message = Errors ::CMAB_FETCH_FAILED % e . message
98
- @logger . error ( error_message )
99
- raise CmabFetchError , error_message
100
- end
84
+ # Perform a single fetch request to the CMAB prediction service.
101
85
102
- if !( 200 ..299 ) . include? ( response . status_code )
103
- error_message = Errors ::CMAB_FETCH_FAILED % response . status_code
104
- @logger . error ( error_message )
105
- raise CmabFetchError , error_message
106
- end
86
+ # Args:
87
+ # url: The endpoint URL.
88
+ # request_body: The request payload.
89
+ # timeout: Maximum wait time for the request to respond in seconds.
90
+ # Returns:
91
+ # The variation ID from the response.
107
92
108
- begin
109
- body = response . json ( )
110
- rescue JSON ::ParserError => e
111
- error_message = Errors ::INVALID_CMAB_FETCH_RESPONSE
112
- @logger . error ( error_message )
113
- raise CmabInvalidResponseError , error_message
114
- end
93
+ headers = { 'Content-Type' => 'application/json' }
94
+ begin
95
+ response = @http_client . post ( url , json : request_body , headers : headers , timeout : timeout )
96
+ rescue StandardError => e
97
+ error_message = Errors ::CMAB_FETCH_FAILED % e . message
98
+ @logger . error ( error_message )
99
+ raise CmabFetchError , error_message
100
+ end
115
101
116
- if !validate_response ( body )
117
- error_message = Errors ::INVALID_CMAB_FETCH_RESPONSE
118
- @logger . error ( error_message )
119
- raise CmabInvalidResponseError , error_message
120
- end
102
+ unless ( 200 ..299 ) . include? ( response . status_code )
103
+ error_message = Errors ::CMAB_FETCH_FAILED % response . status_code
104
+ @logger . error ( error_message )
105
+ raise CmabFetchError , error_message
106
+ end
107
+
108
+ begin
109
+ body = response . json
110
+ rescue JSON ::ParserError
111
+ error_message = Errors ::INVALID_CMAB_FETCH_RESPONSE
112
+ @logger . error ( error_message )
113
+ raise CmabInvalidResponseError , error_message
114
+ end
121
115
122
- return body [ 'predictions' ] [ 0 ] [ 'variationId' ]
116
+ unless validate_response ( body )
117
+ error_message = Errors ::INVALID_CMAB_FETCH_RESPONSE
118
+ @logger . error ( error_message )
119
+ raise CmabInvalidResponseError , error_message
120
+ end
121
+
122
+ body [ 'predictions' ] [ 0 ] [ 'variationId' ]
123
123
end
124
124
125
125
def validate_response ( body )
126
- # Validate the response structure from the CMAB service.
127
- # Args:
128
- # body: The JSON response body to validate.
129
- # Returns:
130
- # true if valid, false otherwise.
131
-
126
+ # Validate the response structure from the CMAB service.
127
+ # Args:
128
+ # body: The JSON response body to validate.
129
+ # Returns:
130
+ # true if valid, false otherwise.
131
+
132
132
body . is_a? ( Hash ) &&
133
133
body . key? ( 'predictions' ) &&
134
134
body [ 'predictions' ] . is_a? ( Array ) &&
135
135
!body [ 'predictions' ] . empty? &&
136
136
body [ 'predictions' ] [ 0 ] . is_a? ( Hash ) &&
137
- body [ 'predictions' ] [ 0 ] . key? ( 'variationId' )
137
+ body [ 'predictions' ] [ 0 ] . key? ( 'variationId' )
138
138
end
139
139
140
140
def _do_fetch_with_retry ( url , request_body , retry_config , timeout )
141
- # Perform a fetch request with retry logic.
142
- # Args:
143
- # url: The endpoint URL.
144
- # request_body: The request payload.
145
- # retry_config: Configuration for retry settings.
146
- # timeout: Maximum wait time for the request to respond in seconds.
147
- # Returns:
148
- # The variation ID from the response.
149
-
150
- backoff = retry_config . initial_backoff
151
-
152
- ( 0 ..retry_config . max_retries ) . each do |attempt |
153
- begin
154
- variation_id = _do_fetch ( url , request_body , timeout )
155
- return variation_id
156
- rescue => e
157
- if attempt < retry_config . max_retries
158
- @logger . info ( "Retrying CMAB request (attempt: #{ attempt + 1 } after #{ backoff } seconds)..." )
159
- sleep ( backoff )
160
- backoff = [ backoff * ( retry_config . backoff_multiplier ** ( attempt + 1 ) ) , retry_config . max_backoff ] . min
161
- end
162
- end
141
+ # Perform a fetch request with retry logic.
142
+ # Args:
143
+ # url: The endpoint URL.
144
+ # request_body: The request payload.
145
+ # retry_config: Configuration for retry settings.
146
+ # timeout: Maximum wait time for the request to respond in seconds.
147
+ # Returns:
148
+ # The variation ID from the response.
149
+
150
+ backoff = retry_config . initial_backoff
151
+
152
+ ( 0 ..retry_config . max_retries ) . each do |attempt |
153
+ variation_id = _do_fetch ( url , request_body , timeout )
154
+ return variation_id
155
+ rescue
156
+ if attempt < retry_config . max_retries
157
+ @logger . info ( "Retrying CMAB request (attempt: #{ attempt + 1 } after #{ backoff } seconds)..." )
158
+ sleep ( backoff )
159
+ backoff = [ backoff * ( retry_config . backoff_multiplier **( attempt + 1 ) ) , retry_config . max_backoff ] . min
163
160
end
161
+ end
164
162
165
- error_message = Errors ::CMAB_FETCH_FAILED % " Max retries exceeded for CMAB request."
166
- @logger . error ( error_message )
167
- raise CmabFetchError , error_message
163
+ error_message = Errors ::CMAB_FETCH_FAILED % ' Max retries exceeded for CMAB request.'
164
+ @logger . error ( error_message )
165
+ raise CmabFetchError , error_message
168
166
end
169
167
end
170
168
end
0 commit comments