temporalio 0.4.0-aarch64-linux-musl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +2 -0
- data/Gemfile +27 -0
- data/Rakefile +101 -0
- data/lib/temporalio/activity/complete_async_error.rb +11 -0
- data/lib/temporalio/activity/context.rb +123 -0
- data/lib/temporalio/activity/definition.rb +192 -0
- data/lib/temporalio/activity/info.rb +67 -0
- data/lib/temporalio/activity.rb +12 -0
- data/lib/temporalio/api/activity/v1/message.rb +25 -0
- data/lib/temporalio/api/batch/v1/message.rb +36 -0
- data/lib/temporalio/api/cloud/account/v1/message.rb +28 -0
- data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +126 -0
- data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +25 -0
- data/lib/temporalio/api/cloud/cloudservice.rb +3 -0
- data/lib/temporalio/api/cloud/identity/v1/message.rb +41 -0
- data/lib/temporalio/api/cloud/namespace/v1/message.rb +42 -0
- data/lib/temporalio/api/cloud/nexus/v1/message.rb +31 -0
- data/lib/temporalio/api/cloud/operation/v1/message.rb +28 -0
- data/lib/temporalio/api/cloud/region/v1/message.rb +24 -0
- data/lib/temporalio/api/cloud/resource/v1/message.rb +23 -0
- data/lib/temporalio/api/cloud/sink/v1/message.rb +24 -0
- data/lib/temporalio/api/cloud/usage/v1/message.rb +31 -0
- data/lib/temporalio/api/command/v1/message.rb +46 -0
- data/lib/temporalio/api/common/v1/grpc_status.rb +23 -0
- data/lib/temporalio/api/common/v1/message.rb +48 -0
- data/lib/temporalio/api/deployment/v1/message.rb +38 -0
- data/lib/temporalio/api/enums/v1/batch_operation.rb +22 -0
- data/lib/temporalio/api/enums/v1/command_type.rb +21 -0
- data/lib/temporalio/api/enums/v1/common.rb +26 -0
- data/lib/temporalio/api/enums/v1/deployment.rb +23 -0
- data/lib/temporalio/api/enums/v1/event_type.rb +21 -0
- data/lib/temporalio/api/enums/v1/failed_cause.rb +26 -0
- data/lib/temporalio/api/enums/v1/namespace.rb +23 -0
- data/lib/temporalio/api/enums/v1/nexus.rb +21 -0
- data/lib/temporalio/api/enums/v1/query.rb +22 -0
- data/lib/temporalio/api/enums/v1/reset.rb +23 -0
- data/lib/temporalio/api/enums/v1/schedule.rb +21 -0
- data/lib/temporalio/api/enums/v1/task_queue.rb +25 -0
- data/lib/temporalio/api/enums/v1/update.rb +22 -0
- data/lib/temporalio/api/enums/v1/workflow.rb +31 -0
- data/lib/temporalio/api/errordetails/v1/message.rb +44 -0
- data/lib/temporalio/api/export/v1/message.rb +24 -0
- data/lib/temporalio/api/failure/v1/message.rb +37 -0
- data/lib/temporalio/api/filter/v1/message.rb +27 -0
- data/lib/temporalio/api/history/v1/message.rb +92 -0
- data/lib/temporalio/api/namespace/v1/message.rb +31 -0
- data/lib/temporalio/api/nexus/v1/message.rb +41 -0
- data/lib/temporalio/api/operatorservice/v1/request_response.rb +49 -0
- data/lib/temporalio/api/operatorservice/v1/service.rb +23 -0
- data/lib/temporalio/api/operatorservice.rb +3 -0
- data/lib/temporalio/api/payload_visitor.rb +1581 -0
- data/lib/temporalio/api/protocol/v1/message.rb +23 -0
- data/lib/temporalio/api/query/v1/message.rb +28 -0
- data/lib/temporalio/api/replication/v1/message.rb +26 -0
- data/lib/temporalio/api/schedule/v1/message.rb +43 -0
- data/lib/temporalio/api/sdk/v1/enhanced_stack_trace.rb +25 -0
- data/lib/temporalio/api/sdk/v1/task_complete_metadata.rb +21 -0
- data/lib/temporalio/api/sdk/v1/user_metadata.rb +23 -0
- data/lib/temporalio/api/sdk/v1/workflow_metadata.rb +23 -0
- data/lib/temporalio/api/taskqueue/v1/message.rb +48 -0
- data/lib/temporalio/api/testservice/v1/request_response.rb +31 -0
- data/lib/temporalio/api/testservice/v1/service.rb +23 -0
- data/lib/temporalio/api/update/v1/message.rb +33 -0
- data/lib/temporalio/api/version/v1/message.rb +26 -0
- data/lib/temporalio/api/workflow/v1/message.rb +51 -0
- data/lib/temporalio/api/workflowservice/v1/request_response.rb +233 -0
- data/lib/temporalio/api/workflowservice/v1/service.rb +23 -0
- data/lib/temporalio/api/workflowservice.rb +3 -0
- data/lib/temporalio/api.rb +15 -0
- data/lib/temporalio/cancellation.rb +170 -0
- data/lib/temporalio/client/activity_id_reference.rb +32 -0
- data/lib/temporalio/client/async_activity_handle.rb +85 -0
- data/lib/temporalio/client/connection/cloud_service.rb +726 -0
- data/lib/temporalio/client/connection/operator_service.rb +201 -0
- data/lib/temporalio/client/connection/service.rb +42 -0
- data/lib/temporalio/client/connection/test_service.rb +111 -0
- data/lib/temporalio/client/connection/workflow_service.rb +1251 -0
- data/lib/temporalio/client/connection.rb +316 -0
- data/lib/temporalio/client/interceptor.rb +455 -0
- data/lib/temporalio/client/schedule.rb +991 -0
- data/lib/temporalio/client/schedule_handle.rb +126 -0
- data/lib/temporalio/client/with_start_workflow_operation.rb +115 -0
- data/lib/temporalio/client/workflow_execution.rb +119 -0
- data/lib/temporalio/client/workflow_execution_count.rb +36 -0
- data/lib/temporalio/client/workflow_execution_status.rb +18 -0
- data/lib/temporalio/client/workflow_handle.rb +389 -0
- data/lib/temporalio/client/workflow_query_reject_condition.rb +14 -0
- data/lib/temporalio/client/workflow_update_handle.rb +65 -0
- data/lib/temporalio/client/workflow_update_wait_stage.rb +17 -0
- data/lib/temporalio/client.rb +607 -0
- data/lib/temporalio/common_enums.rb +41 -0
- data/lib/temporalio/contrib/open_telemetry.rb +470 -0
- data/lib/temporalio/converters/data_converter.rb +99 -0
- data/lib/temporalio/converters/failure_converter.rb +202 -0
- data/lib/temporalio/converters/payload_codec.rb +26 -0
- data/lib/temporalio/converters/payload_converter/binary_null.rb +34 -0
- data/lib/temporalio/converters/payload_converter/binary_plain.rb +35 -0
- data/lib/temporalio/converters/payload_converter/binary_protobuf.rb +42 -0
- data/lib/temporalio/converters/payload_converter/composite.rb +66 -0
- data/lib/temporalio/converters/payload_converter/encoding.rb +35 -0
- data/lib/temporalio/converters/payload_converter/json_plain.rb +44 -0
- data/lib/temporalio/converters/payload_converter/json_protobuf.rb +41 -0
- data/lib/temporalio/converters/payload_converter.rb +71 -0
- data/lib/temporalio/converters/raw_value.rb +20 -0
- data/lib/temporalio/converters.rb +9 -0
- data/lib/temporalio/error/failure.rb +219 -0
- data/lib/temporalio/error.rb +156 -0
- data/lib/temporalio/internal/bridge/3.2/temporalio_bridge.so +0 -0
- data/lib/temporalio/internal/bridge/3.3/temporalio_bridge.so +0 -0
- data/lib/temporalio/internal/bridge/3.4/temporalio_bridge.so +0 -0
- data/lib/temporalio/internal/bridge/api/activity_result/activity_result.rb +34 -0
- data/lib/temporalio/internal/bridge/api/activity_task/activity_task.rb +31 -0
- data/lib/temporalio/internal/bridge/api/child_workflow/child_workflow.rb +33 -0
- data/lib/temporalio/internal/bridge/api/common/common.rb +27 -0
- data/lib/temporalio/internal/bridge/api/core_interface.rb +40 -0
- data/lib/temporalio/internal/bridge/api/external_data/external_data.rb +27 -0
- data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +33 -0
- data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +56 -0
- data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +57 -0
- data/lib/temporalio/internal/bridge/api/workflow_completion/workflow_completion.rb +31 -0
- data/lib/temporalio/internal/bridge/api.rb +3 -0
- data/lib/temporalio/internal/bridge/client.rb +95 -0
- data/lib/temporalio/internal/bridge/runtime.rb +56 -0
- data/lib/temporalio/internal/bridge/testing.rb +69 -0
- data/lib/temporalio/internal/bridge/worker.rb +85 -0
- data/lib/temporalio/internal/bridge.rb +36 -0
- data/lib/temporalio/internal/client/implementation.rb +922 -0
- data/lib/temporalio/internal/metric.rb +122 -0
- data/lib/temporalio/internal/proto_utils.rb +165 -0
- data/lib/temporalio/internal/worker/activity_worker.rb +385 -0
- data/lib/temporalio/internal/worker/multi_runner.rb +213 -0
- data/lib/temporalio/internal/worker/workflow_instance/child_workflow_handle.rb +54 -0
- data/lib/temporalio/internal/worker/workflow_instance/context.rb +383 -0
- data/lib/temporalio/internal/worker/workflow_instance/details.rb +46 -0
- data/lib/temporalio/internal/worker/workflow_instance/external_workflow_handle.rb +32 -0
- data/lib/temporalio/internal/worker/workflow_instance/externally_immutable_hash.rb +22 -0
- data/lib/temporalio/internal/worker/workflow_instance/handler_execution.rb +25 -0
- data/lib/temporalio/internal/worker/workflow_instance/handler_hash.rb +41 -0
- data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +97 -0
- data/lib/temporalio/internal/worker/workflow_instance/inbound_implementation.rb +62 -0
- data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +400 -0
- data/lib/temporalio/internal/worker/workflow_instance/replay_safe_logger.rb +37 -0
- data/lib/temporalio/internal/worker/workflow_instance/replay_safe_metric.rb +40 -0
- data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +183 -0
- data/lib/temporalio/internal/worker/workflow_instance.rb +774 -0
- data/lib/temporalio/internal/worker/workflow_worker.rb +239 -0
- data/lib/temporalio/internal.rb +7 -0
- data/lib/temporalio/metric.rb +109 -0
- data/lib/temporalio/retry_policy.rb +74 -0
- data/lib/temporalio/runtime/metric_buffer.rb +94 -0
- data/lib/temporalio/runtime.rb +352 -0
- data/lib/temporalio/scoped_logger.rb +96 -0
- data/lib/temporalio/search_attributes.rb +356 -0
- data/lib/temporalio/testing/activity_environment.rb +160 -0
- data/lib/temporalio/testing/workflow_environment.rb +406 -0
- data/lib/temporalio/testing.rb +10 -0
- data/lib/temporalio/version.rb +5 -0
- data/lib/temporalio/worker/activity_executor/fiber.rb +49 -0
- data/lib/temporalio/worker/activity_executor/thread_pool.rb +46 -0
- data/lib/temporalio/worker/activity_executor.rb +55 -0
- data/lib/temporalio/worker/interceptor.rb +365 -0
- data/lib/temporalio/worker/thread_pool.rb +237 -0
- data/lib/temporalio/worker/tuner.rb +189 -0
- data/lib/temporalio/worker/workflow_executor/thread_pool.rb +235 -0
- data/lib/temporalio/worker/workflow_executor.rb +26 -0
- data/lib/temporalio/worker/workflow_replayer.rb +350 -0
- data/lib/temporalio/worker.rb +603 -0
- data/lib/temporalio/workflow/activity_cancellation_type.rb +20 -0
- data/lib/temporalio/workflow/child_workflow_cancellation_type.rb +21 -0
- data/lib/temporalio/workflow/child_workflow_handle.rb +43 -0
- data/lib/temporalio/workflow/definition.rb +598 -0
- data/lib/temporalio/workflow/external_workflow_handle.rb +41 -0
- data/lib/temporalio/workflow/future.rb +151 -0
- data/lib/temporalio/workflow/handler_unfinished_policy.rb +13 -0
- data/lib/temporalio/workflow/info.rb +104 -0
- data/lib/temporalio/workflow/parent_close_policy.rb +19 -0
- data/lib/temporalio/workflow/update_info.rb +20 -0
- data/lib/temporalio/workflow.rb +575 -0
- data/lib/temporalio/workflow_history.rb +47 -0
- data/lib/temporalio.rb +11 -0
- data/temporalio.gemspec +29 -0
- metadata +258 -0
@@ -0,0 +1,470 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'English'
|
4
|
+
require 'opentelemetry' # This import will intentionally fail if the user does not have OTel gem available
|
5
|
+
require 'temporalio/client/interceptor'
|
6
|
+
require 'temporalio/converters/payload_converter'
|
7
|
+
require 'temporalio/worker/interceptor'
|
8
|
+
|
9
|
+
module Temporalio
|
10
|
+
module Contrib
|
11
|
+
module OpenTelemetry
|
12
|
+
# Tracing interceptor to add OpenTelemetry traces to clients, activities, and workflows.
|
13
|
+
class TracingInterceptor
|
14
|
+
include Client::Interceptor
|
15
|
+
include Worker::Interceptor::Activity
|
16
|
+
include Worker::Interceptor::Workflow
|
17
|
+
|
18
|
+
# @return [OpenTelemetry::Trace::Tracer] Tracer in use.
|
19
|
+
attr_reader :tracer
|
20
|
+
|
21
|
+
# Create interceptor.
|
22
|
+
#
|
23
|
+
# @param tracer [OpenTelemetry::Trace::Tracer] Tracer to use.
|
24
|
+
# @param header_key [String] Temporal header name to serialize spans to/from. Most users should not change this.
|
25
|
+
# @param propagator [Object] Propagator to use. Most users should not change this.
|
26
|
+
# @param always_create_workflow_spans [Boolean] When false, the default, spans are only created in workflows
|
27
|
+
# when an overarching span from the client is present. In cases of starting a workflow elsewhere, e.g. CLI or
|
28
|
+
# schedules, a client-created span is not present and workflow spans will not be created. Setting this to true
|
29
|
+
# will create spans in workflows no matter what, but there is a risk of them being orphans since they may not
|
30
|
+
# have a parent span after replaying.
|
31
|
+
def initialize(
|
32
|
+
tracer,
|
33
|
+
header_key: '_tracer-data',
|
34
|
+
propagator: ::OpenTelemetry::Context::Propagation::CompositeTextMapPropagator.compose_propagators(
|
35
|
+
[
|
36
|
+
::OpenTelemetry::Trace::Propagation::TraceContext::TextMapPropagator.new,
|
37
|
+
::OpenTelemetry::Baggage::Propagation::TextMapPropagator.new
|
38
|
+
]
|
39
|
+
),
|
40
|
+
always_create_workflow_spans: false
|
41
|
+
)
|
42
|
+
@tracer = tracer
|
43
|
+
@header_key = header_key
|
44
|
+
@propagator = propagator
|
45
|
+
@always_create_workflow_spans = always_create_workflow_spans
|
46
|
+
end
|
47
|
+
|
48
|
+
# @!visibility private
|
49
|
+
def intercept_client(next_interceptor)
|
50
|
+
ClientOutbound.new(self, next_interceptor)
|
51
|
+
end
|
52
|
+
|
53
|
+
# @!visibility private
|
54
|
+
def intercept_activity(next_interceptor)
|
55
|
+
ActivityInbound.new(self, next_interceptor)
|
56
|
+
end
|
57
|
+
|
58
|
+
# @!visibility private
|
59
|
+
def intercept_workflow(next_interceptor)
|
60
|
+
WorkflowInbound.new(self, next_interceptor)
|
61
|
+
end
|
62
|
+
|
63
|
+
# @!visibility private
|
64
|
+
def _apply_context_to_headers(headers, context: ::OpenTelemetry::Context.current)
|
65
|
+
carrier = {}
|
66
|
+
@propagator.inject(carrier, context:)
|
67
|
+
headers[@header_key] = carrier unless carrier.empty?
|
68
|
+
end
|
69
|
+
|
70
|
+
# @!visibility private
|
71
|
+
def _attach_context(headers)
|
72
|
+
context = _context_from_headers(headers)
|
73
|
+
::OpenTelemetry::Context.attach(context) if context
|
74
|
+
end
|
75
|
+
|
76
|
+
# @!visibility private
|
77
|
+
def _context_from_headers(headers)
|
78
|
+
carrier = headers[@header_key]
|
79
|
+
@propagator.extract(carrier) if carrier.is_a?(Hash) && !carrier.empty?
|
80
|
+
end
|
81
|
+
|
82
|
+
# @!visibility private
|
83
|
+
def _with_started_span(
|
84
|
+
name:,
|
85
|
+
kind:,
|
86
|
+
attributes: nil,
|
87
|
+
outbound_input: nil
|
88
|
+
)
|
89
|
+
tracer.in_span(name, attributes:, kind:) do
|
90
|
+
_apply_context_to_headers(outbound_input.headers) if outbound_input
|
91
|
+
yield
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# @!visibility private
|
96
|
+
def _always_create_workflow_spans
|
97
|
+
@always_create_workflow_spans
|
98
|
+
end
|
99
|
+
|
100
|
+
# @!visibility private
|
101
|
+
class ClientOutbound < Client::Interceptor::Outbound
|
102
|
+
def initialize(root, next_interceptor)
|
103
|
+
super(next_interceptor)
|
104
|
+
@root = root
|
105
|
+
end
|
106
|
+
|
107
|
+
# @!visibility private
|
108
|
+
def start_workflow(input)
|
109
|
+
@root._with_started_span(
|
110
|
+
name: "StartWorkflow:#{input.workflow}",
|
111
|
+
kind: :client,
|
112
|
+
attributes: { 'temporalWorkflowID' => input.workflow_id },
|
113
|
+
outbound_input: input
|
114
|
+
) { super }
|
115
|
+
end
|
116
|
+
|
117
|
+
# @!visibility private
|
118
|
+
def start_update_with_start_workflow(input)
|
119
|
+
@root._with_started_span(
|
120
|
+
name: "UpdateWithStartWorkflow:#{input.update}",
|
121
|
+
kind: :client,
|
122
|
+
attributes: { 'temporalWorkflowID' => input.start_workflow_operation.options.id,
|
123
|
+
'temporalUpdateID' => input.update_id },
|
124
|
+
outbound_input: input
|
125
|
+
) do
|
126
|
+
# Also add to start headers
|
127
|
+
if input.headers[@header_key]
|
128
|
+
input.start_workflow_operation.options.headers[@header_key] = input.headers[@header_key]
|
129
|
+
end
|
130
|
+
super
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# @!visibility private
|
135
|
+
def signal_with_start_workflow(input)
|
136
|
+
@root._with_started_span(
|
137
|
+
name: "SignalWithStartWorkflow:#{input.workflow}",
|
138
|
+
kind: :client,
|
139
|
+
attributes: { 'temporalWorkflowID' => input.start_workflow_operation.options.id },
|
140
|
+
outbound_input: input
|
141
|
+
) do
|
142
|
+
# Also add to start headers
|
143
|
+
if input.headers[@header_key]
|
144
|
+
input.start_workflow_operation.options.headers[@header_key] = input.headers[@header_key]
|
145
|
+
end
|
146
|
+
super
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# @!visibility private
|
151
|
+
def signal_workflow(input)
|
152
|
+
@root._with_started_span(
|
153
|
+
name: "SignalWorkflow:#{input.signal}",
|
154
|
+
kind: :client,
|
155
|
+
attributes: { 'temporalWorkflowID' => input.workflow_id },
|
156
|
+
outbound_input: input
|
157
|
+
) { super }
|
158
|
+
end
|
159
|
+
|
160
|
+
# @!visibility private
|
161
|
+
def query_workflow(input)
|
162
|
+
@root._with_started_span(
|
163
|
+
name: "QueryWorkflow:#{input.query}",
|
164
|
+
kind: :client,
|
165
|
+
attributes: { 'temporalWorkflowID' => input.workflow_id },
|
166
|
+
outbound_input: input
|
167
|
+
) { super }
|
168
|
+
end
|
169
|
+
|
170
|
+
# @!visibility private
|
171
|
+
def start_workflow_update(input)
|
172
|
+
@root._with_started_span(
|
173
|
+
name: "StartWorkflowUpdate:#{input.update}",
|
174
|
+
kind: :client,
|
175
|
+
attributes: { 'temporalWorkflowID' => input.workflow_id, 'temporalUpdateID' => input.update_id },
|
176
|
+
outbound_input: input
|
177
|
+
) { super }
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# @!visibility private
|
182
|
+
class ActivityInbound < Worker::Interceptor::Activity::Inbound
|
183
|
+
def initialize(root, next_interceptor)
|
184
|
+
super(next_interceptor)
|
185
|
+
@root = root
|
186
|
+
end
|
187
|
+
|
188
|
+
# @!visibility private
|
189
|
+
def execute(input)
|
190
|
+
@root._attach_context(input.headers)
|
191
|
+
info = Activity::Context.current.info
|
192
|
+
@root._with_started_span(
|
193
|
+
name: "RunActivity:#{info.activity_type}",
|
194
|
+
kind: :server,
|
195
|
+
attributes: {
|
196
|
+
'temporalWorkflowID' => info.workflow_id,
|
197
|
+
'temporalRunID' => info.workflow_run_id,
|
198
|
+
'temporalActivityID' => info.activity_id
|
199
|
+
}
|
200
|
+
) { super }
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# @!visibility private
|
205
|
+
class WorkflowInbound < Worker::Interceptor::Workflow::Inbound
|
206
|
+
def initialize(root, next_interceptor)
|
207
|
+
super(next_interceptor)
|
208
|
+
@root = root
|
209
|
+
end
|
210
|
+
|
211
|
+
# @!visibility private
|
212
|
+
def init(outbound)
|
213
|
+
# Set root on storage
|
214
|
+
Temporalio::Workflow.storage[:__temporal_opentelemetry_tracing_interceptor] = @root
|
215
|
+
super(WorkflowOutbound.new(@root, outbound))
|
216
|
+
end
|
217
|
+
|
218
|
+
# @!visibility private
|
219
|
+
def execute(input)
|
220
|
+
@root._attach_context(Temporalio::Workflow.info.headers)
|
221
|
+
Workflow.with_completed_span("RunWorkflow:#{Temporalio::Workflow.info.workflow_type}", kind: :server) do
|
222
|
+
super
|
223
|
+
ensure
|
224
|
+
Workflow.completed_span(
|
225
|
+
"CompleteWorkflow:#{Temporalio::Workflow.info.workflow_type}",
|
226
|
+
kind: :internal,
|
227
|
+
exception: $ERROR_INFO # steep:ignore
|
228
|
+
)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# @!visibility private
|
233
|
+
def handle_signal(input)
|
234
|
+
@root._attach_context(Temporalio::Workflow.info.headers)
|
235
|
+
Workflow.with_completed_span(
|
236
|
+
"HandleSignal:#{input.signal}",
|
237
|
+
links: _links_from_headers(input.headers),
|
238
|
+
kind: :server
|
239
|
+
) do
|
240
|
+
super
|
241
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
242
|
+
Workflow.completed_span("FailHandleSignal:#{input.signal}", kind: :internal, exception: e)
|
243
|
+
raise
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# @!visibility private
|
248
|
+
def handle_query(input)
|
249
|
+
@root._attach_context(Temporalio::Workflow.info.headers)
|
250
|
+
Workflow.with_completed_span(
|
251
|
+
"HandleQuery:#{input.query}",
|
252
|
+
links: _links_from_headers(input.headers),
|
253
|
+
kind: :server,
|
254
|
+
even_during_replay: true
|
255
|
+
) do
|
256
|
+
super
|
257
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
258
|
+
Workflow.completed_span(
|
259
|
+
"FailHandleQuery:#{input.query}",
|
260
|
+
kind: :internal,
|
261
|
+
exception: e,
|
262
|
+
even_during_replay: true
|
263
|
+
)
|
264
|
+
raise
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
# @!visibility private
|
269
|
+
def validate_update(input)
|
270
|
+
@root._attach_context(Temporalio::Workflow.info.headers)
|
271
|
+
Workflow.with_completed_span(
|
272
|
+
"ValidateUpdate:#{input.update}",
|
273
|
+
attributes: { 'temporalUpdateID' => input.id },
|
274
|
+
links: _links_from_headers(input.headers),
|
275
|
+
kind: :server,
|
276
|
+
even_during_replay: true
|
277
|
+
) do
|
278
|
+
super
|
279
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
280
|
+
Workflow.completed_span(
|
281
|
+
"FailValidateUpdate:#{input.update}",
|
282
|
+
attributes: { 'temporalUpdateID' => input.id },
|
283
|
+
kind: :internal,
|
284
|
+
exception: e,
|
285
|
+
even_during_replay: true
|
286
|
+
)
|
287
|
+
raise
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
# @!visibility private
|
292
|
+
def handle_update(input)
|
293
|
+
@root._attach_context(Temporalio::Workflow.info.headers)
|
294
|
+
Workflow.with_completed_span(
|
295
|
+
"HandleUpdate:#{input.update}",
|
296
|
+
attributes: { 'temporalUpdateID' => input.id },
|
297
|
+
links: _links_from_headers(input.headers),
|
298
|
+
kind: :server
|
299
|
+
) do
|
300
|
+
super
|
301
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
302
|
+
Workflow.completed_span(
|
303
|
+
"FailHandleUpdate:#{input.update}",
|
304
|
+
attributes: { 'temporalUpdateID' => input.id },
|
305
|
+
kind: :internal,
|
306
|
+
exception: e
|
307
|
+
)
|
308
|
+
raise
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
# @!visibility private
|
313
|
+
def _links_from_headers(headers)
|
314
|
+
context = @root._context_from_headers(headers)
|
315
|
+
span = ::OpenTelemetry::Trace.current_span(context) if context
|
316
|
+
if span && span != ::OpenTelemetry::Trace::Span::INVALID
|
317
|
+
[::OpenTelemetry::Trace::Link.new(span.context)]
|
318
|
+
else
|
319
|
+
[]
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# @!visibility private
|
325
|
+
class WorkflowOutbound < Worker::Interceptor::Workflow::Outbound
|
326
|
+
def initialize(root, next_interceptor)
|
327
|
+
super(next_interceptor)
|
328
|
+
@root = root
|
329
|
+
end
|
330
|
+
|
331
|
+
# @!visibility private
|
332
|
+
def execute_activity(input)
|
333
|
+
_apply_span_to_headers(input.headers,
|
334
|
+
Workflow.completed_span("StartActivity:#{input.activity}", kind: :client))
|
335
|
+
super
|
336
|
+
end
|
337
|
+
|
338
|
+
# @!visibility private
|
339
|
+
def execute_local_activity(input)
|
340
|
+
_apply_span_to_headers(input.headers,
|
341
|
+
Workflow.completed_span("StartActivity:#{input.activity}", kind: :client))
|
342
|
+
super
|
343
|
+
end
|
344
|
+
|
345
|
+
# @!visibility private
|
346
|
+
def initialize_continue_as_new_error(input)
|
347
|
+
# Just apply the current context to headers
|
348
|
+
@root._apply_context_to_headers(input.error.headers)
|
349
|
+
super
|
350
|
+
end
|
351
|
+
|
352
|
+
# @!visibility private
|
353
|
+
def signal_child_workflow(input)
|
354
|
+
_apply_span_to_headers(input.headers,
|
355
|
+
Workflow.completed_span("SignalChildWorkflow:#{input.signal}", kind: :client))
|
356
|
+
super
|
357
|
+
end
|
358
|
+
|
359
|
+
# @!visibility private
|
360
|
+
def signal_external_workflow(input)
|
361
|
+
_apply_span_to_headers(input.headers,
|
362
|
+
Workflow.completed_span("SignalExternalWorkflow:#{input.signal}", kind: :client))
|
363
|
+
super
|
364
|
+
end
|
365
|
+
|
366
|
+
# @!visibility private
|
367
|
+
def start_child_workflow(input)
|
368
|
+
_apply_span_to_headers(input.headers,
|
369
|
+
Workflow.completed_span("StartChildWorkflow:#{input.workflow}", kind: :client))
|
370
|
+
super
|
371
|
+
end
|
372
|
+
|
373
|
+
# @!visibility private
|
374
|
+
def _apply_span_to_headers(headers, span)
|
375
|
+
@root._apply_context_to_headers(headers, context: ::OpenTelemetry::Trace.context_with_span(span)) if span
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
private_constant :ClientOutbound
|
380
|
+
private_constant :ActivityInbound
|
381
|
+
private_constant :WorkflowInbound
|
382
|
+
private_constant :WorkflowOutbound
|
383
|
+
end
|
384
|
+
|
385
|
+
# Contains workflow methods that can be used for OpenTelemetry.
|
386
|
+
module Workflow
|
387
|
+
# Create a completed span and execute block with the span set on the context.
|
388
|
+
#
|
389
|
+
# @param name [String] Span name.
|
390
|
+
# @param attributes [Hash] Span attributes. These will have workflow and run ID automatically added.
|
391
|
+
# @param links [Array, nil] Span links.
|
392
|
+
# @param kind [Symbol, nil] Span kind.
|
393
|
+
# @param exception [Exception, nil] Exception to record on the span.
|
394
|
+
# @param even_during_replay [Boolean] Set to true to record this span even during replay. Most users should
|
395
|
+
# never set this.
|
396
|
+
# @yield Block to call. It is UNSAFE to expect any parameters in this block.
|
397
|
+
# @return [Object] Result of the block.
|
398
|
+
def self.with_completed_span(
|
399
|
+
name,
|
400
|
+
attributes: {},
|
401
|
+
links: nil,
|
402
|
+
kind: nil,
|
403
|
+
exception: nil,
|
404
|
+
even_during_replay: false
|
405
|
+
)
|
406
|
+
span = completed_span(name, attributes:, links:, kind:, exception:, even_during_replay:)
|
407
|
+
if span
|
408
|
+
::OpenTelemetry::Trace.with_span(span) do # rubocop:disable Style/ExplicitBlockArgument
|
409
|
+
# Yield with no parameters
|
410
|
+
yield
|
411
|
+
end
|
412
|
+
else
|
413
|
+
yield
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
# Create a completed span only if not replaying (or `even_during_replay` is true).
|
418
|
+
#
|
419
|
+
# @note WARNING: It is UNSAFE to rely on the result of this method as it may be different/absent on replay.
|
420
|
+
#
|
421
|
+
# @param name [String] Span name.
|
422
|
+
# @param attributes [Hash] Span attributes. These will have workflow and run ID automatically added.
|
423
|
+
# @param links [Array, nil] Span links.
|
424
|
+
# @param kind [Symbol, nil] Span kind.
|
425
|
+
# @param exception [Exception, nil] Exception to record on the span.
|
426
|
+
# @param even_during_replay [Boolean] Set to true to record this span even during replay. Most users should
|
427
|
+
# never set this.
|
428
|
+
# @return [OpenTelemetry::Trace::Span, nil] Span if one was created. WARNING: It is UNSAFE to use this value.
|
429
|
+
def self.completed_span(
|
430
|
+
name,
|
431
|
+
attributes: {},
|
432
|
+
links: nil,
|
433
|
+
kind: nil,
|
434
|
+
exception: nil,
|
435
|
+
even_during_replay: false
|
436
|
+
)
|
437
|
+
# Get root interceptor, which also checks if in workflow
|
438
|
+
root = Temporalio::Workflow.storage[:__temporal_opentelemetry_tracing_interceptor] #: TracingInterceptor?
|
439
|
+
raise 'Tracing interceptor not configured' unless root
|
440
|
+
|
441
|
+
# Do nothing if replaying and not wanted during replay
|
442
|
+
return nil if !even_during_replay && Temporalio::Workflow::Unsafe.replaying?
|
443
|
+
|
444
|
+
# If there is no span on the context and the user hasn't opted in to always creating, do not create. This
|
445
|
+
# prevents orphans if there was no span originally created from the client start-workflow call.
|
446
|
+
if ::OpenTelemetry::Trace.current_span == ::OpenTelemetry::Trace::Span::INVALID &&
|
447
|
+
!root._always_create_workflow_spans
|
448
|
+
return nil
|
449
|
+
end
|
450
|
+
|
451
|
+
# Create attributes, adding user-defined ones
|
452
|
+
attributes = { 'temporalWorkflowID' => Temporalio::Workflow.info.workflow_id,
|
453
|
+
'temporalRunID' => Temporalio::Workflow.info.run_id }.merge(attributes)
|
454
|
+
|
455
|
+
# Create span, which has to be done with illegal call disabling because OTel asks for full exception message
|
456
|
+
# which uses error highlighting and such which accesses File#path
|
457
|
+
Temporalio::Workflow::Unsafe.illegal_call_tracing_disabled do
|
458
|
+
time = Temporalio::Workflow.now
|
459
|
+
timestamp = (time.to_i * 1_000_000_000) + time.nsec
|
460
|
+
span = root.tracer.start_span(name, attributes:, links:, start_timestamp: timestamp, kind:) # steep:ignore
|
461
|
+
# Record exception if present
|
462
|
+
span.record_exception(exception) if exception
|
463
|
+
# Finish the span (returns self)
|
464
|
+
span.finish(end_timestamp: timestamp)
|
465
|
+
end
|
466
|
+
end
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|
470
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'temporalio/api'
|
4
|
+
require 'temporalio/converters/failure_converter'
|
5
|
+
require 'temporalio/converters/payload_converter'
|
6
|
+
|
7
|
+
module Temporalio
|
8
|
+
module Converters
|
9
|
+
# Data converter for converting/encoding payloads to/from Ruby values.
|
10
|
+
class DataConverter
|
11
|
+
# @return [PayloadConverter] Payload converter.
|
12
|
+
attr_reader :payload_converter
|
13
|
+
|
14
|
+
# @return [FailureConverter] Failure converter.
|
15
|
+
attr_reader :failure_converter
|
16
|
+
|
17
|
+
# @return [PayloadCodec, nil] Optional codec for encoding/decoding payload bytes such as for encryption.
|
18
|
+
attr_reader :payload_codec
|
19
|
+
|
20
|
+
# @return [DataConverter] Default data converter.
|
21
|
+
def self.default
|
22
|
+
@default ||= DataConverter.new
|
23
|
+
end
|
24
|
+
|
25
|
+
# Create data converter.
|
26
|
+
#
|
27
|
+
# @param payload_converter [PayloadConverter] Payload converter to use.
|
28
|
+
# @param failure_converter [FailureConverter] Failure converter to use.
|
29
|
+
# @param payload_codec [PayloadCodec, nil] Payload codec to use.
|
30
|
+
def initialize(
|
31
|
+
payload_converter: PayloadConverter.default,
|
32
|
+
failure_converter: FailureConverter.default,
|
33
|
+
payload_codec: nil
|
34
|
+
)
|
35
|
+
@payload_converter = payload_converter
|
36
|
+
@failure_converter = failure_converter
|
37
|
+
@payload_codec = payload_codec
|
38
|
+
end
|
39
|
+
|
40
|
+
# Convert a Ruby value to a payload and encode it.
|
41
|
+
#
|
42
|
+
# @param value [Object] Ruby value.
|
43
|
+
# @return [Api::Common::V1::Payload] Converted and encoded payload.
|
44
|
+
def to_payload(value)
|
45
|
+
payload = payload_converter.to_payload(value)
|
46
|
+
payload = payload_codec.encode([payload]).first if payload_codec
|
47
|
+
payload
|
48
|
+
end
|
49
|
+
|
50
|
+
# Convert multiple Ruby values to a payload set and encode it.
|
51
|
+
#
|
52
|
+
# @param values [Object] Ruby values, converted to array via {::Array}.
|
53
|
+
# @return [Api::Common::V1::Payloads] Converted and encoded payload set.
|
54
|
+
def to_payloads(values)
|
55
|
+
payloads = payload_converter.to_payloads(values)
|
56
|
+
payloads.payloads.replace(payload_codec.encode(payloads.payloads)) if payload_codec && !payloads.payloads.empty?
|
57
|
+
payloads
|
58
|
+
end
|
59
|
+
|
60
|
+
# Decode and convert a payload to a Ruby value.
|
61
|
+
#
|
62
|
+
# @param payload [Api::Common::V1::Payload] Encoded payload.
|
63
|
+
# @return [Object] Decoded and converted Ruby value.
|
64
|
+
def from_payload(payload)
|
65
|
+
payload = payload_codec.decode([payload]).first if payload_codec
|
66
|
+
payload_converter.from_payload(payload)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Decode and convert a payload set to Ruby values.
|
70
|
+
#
|
71
|
+
# @param payloads [Api::Common::V1::Payloads, nil] Encoded payload set.
|
72
|
+
# @return [Array<Object>] Decoded and converted Ruby values.
|
73
|
+
def from_payloads(payloads)
|
74
|
+
return [] unless payloads && !payloads.payloads.empty?
|
75
|
+
|
76
|
+
if payload_codec && !payloads.payloads.empty?
|
77
|
+
payloads = Api::Common::V1::Payloads.new(payloads: payload_codec.decode(payloads.payloads))
|
78
|
+
end
|
79
|
+
payload_converter.from_payloads(payloads)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Convert a Ruby error to a Temporal failure and encode it.
|
83
|
+
#
|
84
|
+
# @param error [Exception] Ruby error.
|
85
|
+
# @return [Api::Failure::V1::Failure] Converted and encoded failure.
|
86
|
+
def to_failure(error)
|
87
|
+
failure_converter.to_failure(error, self)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Decode and convert a Temporal failure to a Ruby error.
|
91
|
+
#
|
92
|
+
# @param failure [Api::Failure::V1::Failure] Encoded failure.
|
93
|
+
# @return [Exception] Decoded and converted Ruby error.
|
94
|
+
def from_failure(failure)
|
95
|
+
failure_converter.from_failure(failure, self)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|