Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix failed action attempt handling, add custom action attempt errors #61

Merged
merged 12 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/seam.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
require_relative "seam/client"
require_relative "seam/base_client"
require_relative "seam/base_resource"
require_relative "seam/errors"

require_relative "seam/routes/resources/index"
require_relative "seam/routes/clients/index"
Expand Down
2 changes: 1 addition & 1 deletion lib/seam/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Client
attr_accessor :wait_for_action_attempt, :defaults

def initialize(api_key: nil, personal_access_token: nil, workspace_id: nil, endpoint: nil,
wait_for_action_attempt: false, debug: false)
wait_for_action_attempt: true, debug: false)
options = SeamOptions.parse_options(api_key: api_key, personal_access_token: personal_access_token, workspace_id: workspace_id, endpoint: endpoint)
@endpoint = options[:endpoint]
@auth_headers = options[:auth_headers]
Expand Down
61 changes: 61 additions & 0 deletions lib/seam/errors.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# frozen_string_literal: true

module Seam
module Errors
# HTTP
class SeamHttpApiError < StandardError
attr_reader :code, :status_code, :request_id, :data

def initialize(error, status_code, request_id)
super(error[:message])
@code = error[:type]
@status_code = status_code
@request_id = request_id
@data = error[:data]
end
end

class SeamHttpUnauthorizedError < SeamHttpApiError
def initialize(request_id)
super({type: "unauthorized", message: "Unauthorized"}, 401, request_id)
end
end

class SeamHttpInvalidInputError < SeamHttpApiError
andrii-balitskyi marked this conversation as resolved.
Show resolved Hide resolved
def initialize(error, status_code, request_id)
super(error, status_code, request_id)
@code = "invalid_input"
end
end

# Action attempt
class SeamActionAttemptError < StandardError
attr_reader :action_attempt

def initialize(message, action_attempt)
super(message)
@action_attempt = action_attempt
end

def name
self.class.name
end
end

class SeamActionAttemptFailedError < SeamActionAttemptError
attr_reader :code

def initialize(action_attempt)
super(action_attempt.error.message, action_attempt)
@code = action_attempt.error.type
end
end

class SeamActionAttemptTimeoutError < SeamActionAttemptError
def initialize(action_attempt, timeout)
message = "Timed out waiting for action attempt after #{timeout}s"
super(message, action_attempt)
end
end
end
end
41 changes: 3 additions & 38 deletions lib/seam/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,6 @@ module Seam
class Request
attr_reader :endpoint, :debug

class Error < StandardError
attr_reader :status, :response

def initialize(message, status, response)
super(message)
@status = status
@response = response
end
end

def initialize(auth_headers:, endpoint:, debug: false)
@auth_headers = auth_headers
@endpoint = endpoint
Expand Down Expand Up @@ -44,7 +34,7 @@ def handle_error_response(response, _method, _uri)
status_code = response.status.code
request_id = response.headers["seam-request-id"]

raise SeamHttpUnauthorizedError.new(request_id) if status_code == 401
raise Errors::SeamHttpUnauthorizedError.new(request_id) if status_code == 401

error = response.parse["error"] || {}
error_type = error["type"] || "unknown_error"
Expand All @@ -54,9 +44,9 @@ def handle_error_response(response, _method, _uri)
data: error["data"]
}

raise SeamHttpInvalidInputError.new(error_details, status_code, request_id) if error_type == "invalid_input"
raise Errors::SeamHttpInvalidInputError.new(error_details, status_code, request_id) if error_type == "invalid_input"

raise SeamHttpApiError.new(error_details, status_code, request_id)
raise Errors::SeamHttpApiError.new(error_details, status_code, request_id)
razor-x marked this conversation as resolved.
Show resolved Hide resolved
end

def build_url(uri)
Expand All @@ -77,29 +67,4 @@ def user_agent
"seam-ruby/#{Seam::VERSION}"
end
end

class SeamHttpApiError < StandardError
attr_reader :code, :status_code, :request_id, :data

def initialize(error, status_code, request_id)
super(error[:message])
@code = error[:type]
@status_code = status_code
@request_id = request_id
@data = error[:data]
end
end

class SeamHttpUnauthorizedError < SeamHttpApiError
def initialize(request_id)
super({type: "unauthorized", message: "Unauthorized"}, 401, request_id)
end
end

class SeamHttpInvalidInputError < SeamHttpApiError
def initialize(error, status_code, request_id)
super(error, status_code, request_id)
@code = "invalid_input"
end
end
end
11 changes: 7 additions & 4 deletions lib/seam/utils/action_attempt_utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,23 @@ def self.decide_and_wait(action_attempt, client, wait_for_action_attempt)
end
end

def self.wait_until_finished(action_attempt, client, timeout: 5.0, polling_interval: 0.5)
def self.wait_until_finished(action_attempt, client, timeout: nil, polling_interval: nil)
timeout = timeout.nil? ? 5.0 : timeout
polling_interval = polling_interval.nil? ? 0.5 : polling_interval

time_waiting = 0.0

while action_attempt.status == "pending"
sleep(polling_interval)
time_waiting += polling_interval

raise "Timed out waiting for action attempt to be finished" if time_waiting > timeout
raise Errors::SeamActionAttemptTimeoutError.new(action_attempt, timeout) if time_waiting > timeout

action_attempt = update_action_attempt(action_attempt, client)

raise "Action Attempt failed: #{action_attempt.error["message"]}" if action_attempt.status == "failed"
end

raise Errors::SeamActionAttemptFailedError.new(action_attempt) if action_attempt.status == "error"

action_attempt
end

Expand Down
4 changes: 2 additions & 2 deletions spec/request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

it "parses the error" do
expect { client.health }.to raise_error do |error|
expect(error).to be_a(Seam::SeamHttpApiError)
expect(error).to be_a(Seam::Errors::SeamHttpApiError)
expect(error.message).to eq(message)
expect(error.code).to eq(type)
expect(error.request_id).to eq(request_id)
Expand All @@ -48,7 +48,7 @@

it "parses the error" do
expect { client.health }.to raise_error do |error|
expect(error).to be_a(Seam::SeamHttpApiError)
expect(error).to be_a(Seam::Errors::SeamHttpApiError)
expect(error.message).to eq(message)
expect(error.code).to eq(type)
expect(error.request_id).to eq(request_id)
Expand Down
23 changes: 0 additions & 23 deletions spec/resources/action_attempt_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,29 +73,6 @@
it "returns an updated ActionAttempt" do
expect(result.status).to eq(finished_status)
end

context "when action attempt fails" do
let(:status) { "failed" }
let(:error_message) { "Something went wrong" }

before do
stub_seam_request(
:post,
"/action_attempts/get",
{action_attempt: action_attempt_hash.merge(status: status, error: {"message" => error_message})}
)
end

it "raises an error" do
expect { described_class.wait_until_finished(action_attempt, client) }.to raise_error("Action Attempt failed: #{error_message}")
end
end

context "when timeout is reached" do
it "raises a timeout error" do
expect { described_class.wait_until_finished(action_attempt, client, timeout: 0.1) }.to raise_error("Timed out waiting for action attempt to be finished")
end
end
end

describe ".update_action_attempt" do
Expand Down
2 changes: 1 addition & 1 deletion spec/seam_client/init_seam_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
describe "#initialize" do
it "initializes Seam with fixture" do
expect(seam.lts_version).not_to be_nil
expect(seam.wait_for_action_attempt).to be_falsey
expect(seam.wait_for_action_attempt).to be true
end
end
end
6 changes: 3 additions & 3 deletions spec/seam_client/request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
end

it "raises SeamHttpUnauthorizedError" do
expect { seam.devices.list }.to raise_error(Seam::SeamHttpUnauthorizedError) do |error|
expect { seam.devices.list }.to raise_error(Seam::Errors::SeamHttpUnauthorizedError) do |error|
expect(error.message).to eq("Unauthorized")
expect(error.request_id).to eq(request_id)
end
Expand All @@ -37,7 +37,7 @@
end

it "raises SeamHttpInvalidInputError" do
expect { seam.devices.get(device_id: "invalid_device_id") }.to raise_error(Seam::SeamHttpInvalidInputError) do |error|
expect { seam.devices.get(device_id: "invalid_device_id") }.to raise_error(Seam::Errors::SeamHttpInvalidInputError) do |error|
expect(error.message).to eq(error_message)
expect(error.status_code).to eq(error_status)
expect(error.request_id).to eq(request_id)
Expand All @@ -64,7 +64,7 @@
end

it "raises SeamHttpApiError with the correct details" do
expect { seam.devices.list }.to raise_error(Seam::SeamHttpApiError) do |error|
expect { seam.devices.list }.to raise_error(Seam::Errors::SeamHttpApiError) do |error|
expect(error.message).to eq(error_message)
expect(error.status_code).to eq(error_status)
expect(error.request_id).to eq(request_id)
Expand Down
Loading