-
Notifications
You must be signed in to change notification settings - Fork 110
Expand file tree
/
Copy patherrors.rb
More file actions
107 lines (100 loc) · 5.09 KB
/
errors.rb
File metadata and controls
107 lines (100 loc) · 5.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
require 'temporal/errors'
module Temporal
class Workflow
class Errors
# Convert a failure returned from the server to an Error to raise to the client
# failure: Temporalio::Api::Failure::V1::Failure
def self.generate_error(failure, converter, default_exception_class = StandardError)
case failure.failure_info
when :application_failure_info
error_type = failure.application_failure_info.type
exception_class = safe_constantize(error_type)
message = failure.message
if exception_class.nil?
Temporal.logger.error(
'Could not find original error class. Defaulting to StandardError.',
{ original_error: error_type }
)
message = "#{error_type}: #{failure.message}"
exception_class = default_exception_class
end
begin
details = failure.application_failure_info.details
exception_or_message = converter.from_details_payloads(details)
# v1 serialization only supports StandardErrors with a single "message" argument.
# v2 serialization supports complex errors using our converters to serialize them.
# enable v2 serialization in activities with Temporal::Configuration#use_error_serialization_v2
if exception_or_message.is_a?(Exception)
exception = exception_or_message
else
exception = exception_class.new(message)
end
rescue StandardError => deserialization_error
message = "#{exception_class}: #{message}"
exception = default_exception_class.new(message)
Temporal.logger.error(
"Could not instantiate original error. Defaulting to StandardError. Make sure the worker running " \
"your activities is configured with use_error_serialization_v2. If so, make sure the " \
"original error serialized by searching your logs for 'unserializable_error'. If not, you're using "\
"legacy serialization, and it's likely that "\
"your error's initializer takes something other than exactly one positional argument.",
{
original_error: error_type,
serialized_error: details.payloads.first.data,
instantiation_error_class: deserialization_error.class.to_s,
instantiation_error_message: deserialization_error.message,
},
)
end
exception.tap do |exception|
backtrace = failure.stack_trace.split("\n")
exception.set_backtrace(backtrace) if !backtrace.empty?
end
when :timeout_failure_info
TimeoutError.new("Timeout type: #{failure.timeout_failure_info.timeout_type.to_s}")
when :canceled_failure_info
# TODO: Distinguish between different entity cancellations
StandardError.new(converter.from_payloads(failure.canceled_failure_info.details))
else
StandardError.new(failure.message)
end
end
WORKFLOW_ALREADY_EXISTS_SYM = Temporalio::Api::Enums::V1::StartChildWorkflowExecutionFailedCause.lookup(
Temporalio::Api::Enums::V1::StartChildWorkflowExecutionFailedCause::START_CHILD_WORKFLOW_EXECUTION_FAILED_CAUSE_WORKFLOW_ALREADY_EXISTS
)
def self.generate_error_for_child_workflow_start(cause, workflow_id)
if cause == WORKFLOW_ALREADY_EXISTS_SYM
Temporal::WorkflowExecutionAlreadyStartedFailure.new(
"The child workflow could not be started - per its workflow_id_reuse_policy, it conflicts with another workflow with the same id: #{workflow_id}",
)
else
# Right now, there's only one cause, but temporal may add more in the future
StandardError.new("The child workflow could not be started. Reason: #{cause}")
end
end
def self.generate_error_for_external_signal(cause:, namespace:, workflow_id:)
case cause
when :SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED_CAUSE_EXTERNAL_WORKFLOW_EXECUTION_NOT_FOUND
Temporal::ExternalSignalExecutionNotFoundError.new(
"Failed to send external signal because execution with workflow ID '#{workflow_id}' could not be found or has already completed"
)
when :SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED_CAUSE_NAMESPACE_NOT_FOUND
Temporal::ExternalSignalNamespaceNotFoundError.new(
"Failed to send external signal because namespace #{namespace} could not be found"
)
when :SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED_CAUSE_SIGNAL_COUNT_LIMIT_EXCEEDED
Temporal::ExternalSignalLimitExceededError.new(
"Failed to send external signal because per workflow limit was exceeded"
)
else
Temporal::ExternalSignalError.new("Failed to send external workflow signal with unknown cause: #{cause}")
end
end
private_class_method def self.safe_constantize(const)
Object.const_get(const) if Object.const_defined?(const)
rescue NameError
nil
end
end
end
end