Skip to content

Commit 4aea845

Browse files
author
swaroopakkineni
committed
Fix retry logic syntax error and add RetryableError exception
1 parent 2ff7955 commit 4aea845

File tree

4 files changed

+29
-18
lines changed

4 files changed

+29
-18
lines changed

lib/workos/audit_logs.rb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ class << self
2020
# @return [nil]
2121
def create_event(organization:, event:, idempotency_key: nil)
2222
# Auto-generate idempotency key if not provided
23-
if idempotency_key.nil?
24-
idempotency_key = SecureRandom.uuid
25-
end
23+
idempotency_key = SecureRandom.uuid if idempotency_key.nil?
2624

2725
request = post_request(
2826
path: '/audit_logs/events',

lib/workos/client.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ def client
1414
end
1515
end
1616

17+
# rubocop:disable Metrics/AbcSize
1718
def execute_request(request:)
1819
retries = WorkOS.config.max_retries
1920
attempt = 0
@@ -27,14 +28,14 @@ def execute_request(request:)
2728
attempt += 1
2829
delay = calculate_retry_delay(attempt, response)
2930
sleep(delay)
30-
retry
31+
raise RetryableError.new(http_status: http_status)
3132
else
3233
handle_error_response(response: response)
3334
end
3435
end
3536

3637
response
37-
rescue Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout => e
38+
rescue Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout
3839
if attempt < retries
3940
attempt += 1
4041
delay = calculate_backoff(attempt)
@@ -45,8 +46,11 @@ def execute_request(request:)
4546
message: 'API Timeout Error',
4647
)
4748
end
49+
rescue RetryableError
50+
retry
4851
end
4952
end
53+
# rubocop:enable Metrics/AbcSize
5054

5155
def get_request(path:, auth: false, params: {}, access_token: nil)
5256
uri = URI(path)

lib/workos/errors.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,14 @@ class NotFoundError < WorkOSError; end
8989

9090
# UnprocessableEntityError is raised when a request is made that cannot be processed
9191
class UnprocessableEntityError < WorkOSError; end
92+
93+
# RetryableError is raised internally to trigger retry logic for retryable HTTP errors
94+
class RetryableError < StandardError
95+
attr_reader :http_status
96+
97+
def initialize(http_status:)
98+
@http_status = http_status
99+
super()
100+
end
101+
end
92102
end

spec/lib/workos/client_retry_spec.rb

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def self.test_request
2323
it 'retries up to max_retries times' do
2424
allow(test_module).to receive(:client).and_return(double('client'))
2525
allow(test_module.client).to receive(:request) do
26-
double('response', code: '500', body: '{"message": "Internal Server Error"}')
26+
double('response', code: '500', body: '{"message": "Internal Server Error"}', '[]': nil)
2727
end
2828

2929
expect(test_module.client).to receive(:request).exactly(4).times
@@ -39,7 +39,7 @@ def self.test_request
3939
it 'retries on service unavailable' do
4040
allow(test_module).to receive(:client).and_return(double('client'))
4141
allow(test_module.client).to receive(:request) do
42-
double('response', code: '503', body: '{"message": "Service Unavailable"}')
42+
double('response', code: '503', body: '{"message": "Service Unavailable"}', '[]': nil)
4343
end
4444

4545
expect(test_module.client).to receive(:request).exactly(4).times
@@ -195,27 +195,27 @@ def self.test_request
195195
# Allow rand to return a consistent value for testing
196196
allow_any_instance_of(Object).to receive(:rand).and_return(0.5)
197197

198-
backoff_1 = test_module.send(:calculate_backoff, 1)
199-
backoff_2 = test_module.send(:calculate_backoff, 2)
200-
backoff_3 = test_module.send(:calculate_backoff, 3)
198+
backoff_attempt_1 = test_module.send(:calculate_backoff, 1)
199+
backoff_attempt_2 = test_module.send(:calculate_backoff, 2)
200+
backoff_attempt_3 = test_module.send(:calculate_backoff, 3)
201201

202202
# Attempt 1: base_delay * 2^0 = 1.0, jitter = 0.125
203-
expect(backoff_1).to eq(1.125)
203+
expect(backoff_attempt_1).to eq(1.125)
204204

205205
# Attempt 2: base_delay * 2^1 = 2.0, jitter = 0.25
206-
expect(backoff_2).to eq(2.25)
206+
expect(backoff_attempt_2).to eq(2.25)
207207

208208
# Attempt 3: base_delay * 2^2 = 4.0, jitter = 0.5
209-
expect(backoff_3).to eq(4.5)
209+
expect(backoff_attempt_3).to eq(4.5)
210210
end
211211

212212
it 'respects max_delay' do
213213
allow_any_instance_of(Object).to receive(:rand).and_return(0.5)
214214

215-
backoff_10 = test_module.send(:calculate_backoff, 10)
215+
backoff_attempt_10 = test_module.send(:calculate_backoff, 10)
216216

217217
# Should cap at 30.0 + jitter (30.0 * 0.25 * 0.5 = 3.75)
218-
expect(backoff_10).to eq(33.75)
218+
expect(backoff_attempt_10).to eq(33.75)
219219
end
220220
end
221221

@@ -225,7 +225,7 @@ def self.test_request
225225

226226
allow(test_module).to receive(:client).and_return(double('client'))
227227
allow(test_module.client).to receive(:request) do
228-
double('response', code: '500', body: '{"message": "Internal Server Error"}')
228+
double('response', code: '500', body: '{"message": "Internal Server Error"}', '[]': nil)
229229
end
230230

231231
expect(test_module.client).to receive(:request).exactly(3).times
@@ -243,7 +243,7 @@ def self.test_request
243243

244244
allow(test_module).to receive(:client).and_return(double('client'))
245245
allow(test_module.client).to receive(:request) do
246-
double('response', code: '500', body: '{"message": "Internal Server Error"}')
246+
double('response', code: '500', body: '{"message": "Internal Server Error"}', '[]': nil)
247247
end
248248

249249
expect(test_module.client).to receive(:request).once
@@ -277,4 +277,3 @@ def self.test_request
277277
end
278278
end
279279
end
280-

0 commit comments

Comments
 (0)