temporal-ruby 0.0.1.pre.pre1 → 0.0.1
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 +4 -4
- data/Gemfile +2 -0
- data/README.md +23 -3
- data/lib/gen/temporal/api/command/v1/message_pb.rb +1 -1
- data/lib/gen/temporal/api/enums/v1/common_pb.rb +7 -0
- data/lib/gen/temporal/api/errordetails/v1/message_pb.rb +5 -6
- data/lib/gen/temporal/api/version/v1/message_pb.rb +19 -8
- data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +19 -8
- data/lib/gen/temporal/api/workflowservice/v1/service_services_pb.rb +0 -3
- data/lib/temporal.rb +104 -0
- data/lib/temporal/activity/context.rb +5 -1
- data/lib/temporal/activity/poller.rb +26 -9
- data/lib/temporal/activity/task_processor.rb +33 -20
- data/lib/temporal/client/converter/base.rb +35 -0
- data/lib/temporal/client/converter/composite.rb +49 -0
- data/lib/temporal/client/converter/payload/bytes.rb +30 -0
- data/lib/temporal/client/converter/payload/json.rb +28 -0
- data/lib/temporal/client/converter/payload/nil.rb +27 -0
- data/lib/temporal/client/grpc_client.rb +102 -27
- data/lib/temporal/client/retryer.rb +49 -0
- data/lib/temporal/client/serializer.rb +2 -0
- data/lib/temporal/client/serializer/cancel_timer.rb +2 -2
- data/lib/temporal/client/serializer/complete_workflow.rb +6 -4
- data/lib/temporal/client/serializer/continue_as_new.rb +37 -0
- data/lib/temporal/client/serializer/fail_workflow.rb +2 -2
- data/lib/temporal/client/serializer/failure.rb +4 -2
- data/lib/temporal/client/serializer/record_marker.rb +6 -4
- data/lib/temporal/client/serializer/request_activity_cancellation.rb +2 -2
- data/lib/temporal/client/serializer/retry_policy.rb +24 -0
- data/lib/temporal/client/serializer/schedule_activity.rb +8 -20
- data/lib/temporal/client/serializer/start_child_workflow.rb +9 -20
- data/lib/temporal/client/serializer/start_timer.rb +2 -2
- data/lib/temporal/concerns/payloads.rb +51 -0
- data/lib/temporal/configuration.rb +31 -4
- data/lib/temporal/error_handler.rb +11 -0
- data/lib/temporal/errors.rb +24 -0
- data/lib/temporal/execution_options.rb +9 -1
- data/lib/temporal/json.rb +3 -1
- data/lib/temporal/logger.rb +17 -0
- data/lib/temporal/metadata.rb +11 -3
- data/lib/temporal/metadata/activity.rb +15 -2
- data/lib/temporal/metadata/workflow.rb +8 -0
- data/lib/temporal/metadata/workflow_task.rb +11 -0
- data/lib/temporal/retry_policy.rb +6 -9
- data/lib/temporal/saga/concern.rb +1 -1
- data/lib/temporal/testing.rb +1 -0
- data/lib/temporal/testing/future_registry.rb +1 -1
- data/lib/temporal/testing/local_activity_context.rb +1 -1
- data/lib/temporal/testing/local_workflow_context.rb +38 -14
- data/lib/temporal/testing/scheduled_workflows.rb +75 -0
- data/lib/temporal/testing/temporal_override.rb +35 -7
- data/lib/temporal/testing/workflow_override.rb +6 -1
- data/lib/temporal/version.rb +1 -1
- data/lib/temporal/worker.rb +28 -10
- data/lib/temporal/workflow.rb +8 -2
- data/lib/temporal/workflow/command.rb +3 -0
- data/lib/temporal/workflow/context.rb +40 -5
- data/lib/temporal/workflow/errors.rb +39 -0
- data/lib/temporal/workflow/executor.rb +1 -1
- data/lib/temporal/workflow/future.rb +18 -6
- data/lib/temporal/workflow/history/event.rb +1 -3
- data/lib/temporal/workflow/history/event_target.rb +4 -0
- data/lib/temporal/workflow/history/window.rb +1 -1
- data/lib/temporal/workflow/poller.rb +41 -13
- data/lib/temporal/workflow/replay_aware_logger.rb +4 -4
- data/lib/temporal/workflow/state_manager.rb +33 -52
- data/lib/temporal/workflow/task_processor.rb +41 -11
- metadata +21 -9
- data/lib/temporal/client/serializer/payload.rb +0 -25
@@ -2,18 +2,22 @@ require 'temporal/client'
|
|
2
2
|
require 'temporal/thread_pool'
|
3
3
|
require 'temporal/middleware/chain'
|
4
4
|
require 'temporal/activity/task_processor'
|
5
|
+
require 'temporal/error_handler'
|
5
6
|
|
6
7
|
module Temporal
|
7
8
|
class Activity
|
8
9
|
class Poller
|
9
|
-
|
10
|
+
DEFAULT_OPTIONS = {
|
11
|
+
thread_pool_size: 20
|
12
|
+
}.freeze
|
10
13
|
|
11
|
-
def initialize(namespace, task_queue, activity_lookup, middleware = [])
|
14
|
+
def initialize(namespace, task_queue, activity_lookup, middleware = [], options = {})
|
12
15
|
@namespace = namespace
|
13
16
|
@task_queue = task_queue
|
14
17
|
@activity_lookup = activity_lookup
|
15
18
|
@middleware = middleware
|
16
19
|
@shutting_down = false
|
20
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
17
21
|
end
|
18
22
|
|
19
23
|
def start
|
@@ -21,18 +25,23 @@ module Temporal
|
|
21
25
|
@thread = Thread.new(&method(:poll_loop))
|
22
26
|
end
|
23
27
|
|
24
|
-
def
|
28
|
+
def stop_polling
|
25
29
|
@shutting_down = true
|
26
|
-
|
30
|
+
Temporal.logger.info('Shutting down activity poller', { namespace: namespace, task_queue: task_queue })
|
31
|
+
end
|
32
|
+
|
33
|
+
def cancel_pending_requests
|
34
|
+
client.cancel_polling_request
|
27
35
|
end
|
28
36
|
|
29
37
|
def wait
|
30
38
|
thread.join
|
39
|
+
thread_pool.shutdown
|
31
40
|
end
|
32
41
|
|
33
42
|
private
|
34
43
|
|
35
|
-
attr_reader :namespace, :task_queue, :activity_lookup, :middleware, :thread
|
44
|
+
attr_reader :namespace, :task_queue, :activity_lookup, :middleware, :options, :thread
|
36
45
|
|
37
46
|
def client
|
38
47
|
@client ||= Temporal::Client.generate
|
@@ -43,14 +52,20 @@ module Temporal
|
|
43
52
|
end
|
44
53
|
|
45
54
|
def poll_loop
|
55
|
+
last_poll_time = Time.now
|
56
|
+
metrics_tags = { namespace: namespace, task_queue: task_queue }.freeze
|
57
|
+
|
46
58
|
loop do
|
47
59
|
thread_pool.wait_for_available_threads
|
48
60
|
|
49
61
|
return if shutting_down?
|
50
62
|
|
51
|
-
|
63
|
+
time_diff_ms = ((Time.now - last_poll_time) * 1000).round
|
64
|
+
Temporal.metrics.timing('activity_poller.time_since_last_poll', time_diff_ms, metrics_tags)
|
65
|
+
Temporal.logger.debug("Polling activity task queue", { namespace: namespace, task_queue: task_queue })
|
52
66
|
|
53
67
|
task = poll_for_task
|
68
|
+
last_poll_time = Time.now
|
54
69
|
next unless task&.activity_type
|
55
70
|
|
56
71
|
thread_pool.schedule { process(task) }
|
@@ -60,19 +75,21 @@ module Temporal
|
|
60
75
|
def poll_for_task
|
61
76
|
client.poll_activity_task_queue(namespace: namespace, task_queue: task_queue)
|
62
77
|
rescue StandardError => error
|
63
|
-
Temporal.logger.error("Unable to poll activity task queue:
|
78
|
+
Temporal.logger.error("Unable to poll activity task queue", { namespace: namespace, task_queue: task_queue, error: error.inspect })
|
79
|
+
|
80
|
+
Temporal::ErrorHandler.handle(error)
|
81
|
+
|
64
82
|
nil
|
65
83
|
end
|
66
84
|
|
67
85
|
def process(task)
|
68
|
-
client = Temporal::Client.generate
|
69
86
|
middleware_chain = Middleware::Chain.new(middleware)
|
70
87
|
|
71
88
|
TaskProcessor.new(task, namespace, activity_lookup, client, middleware_chain).process
|
72
89
|
end
|
73
90
|
|
74
91
|
def thread_pool
|
75
|
-
@thread_pool ||= ThreadPool.new(
|
92
|
+
@thread_pool ||= ThreadPool.new(options[:thread_pool_size])
|
76
93
|
end
|
77
94
|
end
|
78
95
|
end
|
@@ -1,14 +1,19 @@
|
|
1
1
|
require 'temporal/metadata'
|
2
|
+
require 'temporal/error_handler'
|
2
3
|
require 'temporal/errors'
|
3
4
|
require 'temporal/activity/context'
|
4
|
-
require 'temporal/
|
5
|
+
require 'temporal/concerns/payloads'
|
6
|
+
require 'temporal/client/retryer'
|
5
7
|
|
6
8
|
module Temporal
|
7
9
|
class Activity
|
8
10
|
class TaskProcessor
|
11
|
+
include Concerns::Payloads
|
12
|
+
|
9
13
|
def initialize(task, namespace, activity_lookup, client, middleware_chain)
|
10
14
|
@task = task
|
11
15
|
@namespace = namespace
|
16
|
+
@metadata = Metadata.generate(Metadata::ACTIVITY_TYPE, task, namespace)
|
12
17
|
@task_token = task.task_token
|
13
18
|
@activity_name = task.activity_type.name
|
14
19
|
@activity_class = activity_lookup.find(activity_name)
|
@@ -19,33 +24,34 @@ module Temporal
|
|
19
24
|
def process
|
20
25
|
start_time = Time.now
|
21
26
|
|
22
|
-
Temporal.logger.
|
27
|
+
Temporal.logger.debug("Processing Activity task", metadata.to_h)
|
23
28
|
Temporal.metrics.timing('activity_task.queue_time', queue_time_ms, activity: activity_name)
|
24
29
|
|
30
|
+
context = Activity::Context.new(client, metadata)
|
31
|
+
|
25
32
|
if !activity_class
|
26
33
|
raise ActivityNotRegistered, 'Activity is not registered with this worker'
|
27
34
|
end
|
28
35
|
|
29
|
-
metadata = Metadata.generate(Metadata::ACTIVITY_TYPE, task, namespace)
|
30
|
-
context = Activity::Context.new(client, metadata)
|
31
|
-
|
32
36
|
result = middleware_chain.invoke(metadata) do
|
33
|
-
activity_class.execute_in_context(context,
|
37
|
+
activity_class.execute_in_context(context, from_payloads(task.input))
|
34
38
|
end
|
35
39
|
|
36
40
|
# Do not complete asynchronous activities, these should be completed manually
|
37
41
|
respond_completed(result) unless context.async?
|
38
42
|
rescue StandardError, ScriptError => error
|
43
|
+
Temporal::ErrorHandler.handle(error, metadata: metadata)
|
44
|
+
|
39
45
|
respond_failed(error)
|
40
46
|
ensure
|
41
47
|
time_diff_ms = ((Time.now - start_time) * 1000).round
|
42
48
|
Temporal.metrics.timing('activity_task.latency', time_diff_ms, activity: activity_name)
|
43
|
-
Temporal.logger.debug("Activity task processed
|
49
|
+
Temporal.logger.debug("Activity task processed", metadata.to_h.merge(execution_time: time_diff_ms))
|
44
50
|
end
|
45
51
|
|
46
52
|
private
|
47
53
|
|
48
|
-
attr_reader :task, :namespace, :task_token, :activity_name, :activity_class, :client, :middleware_chain
|
54
|
+
attr_reader :task, :namespace, :task_token, :activity_name, :activity_class, :client, :middleware_chain, :metadata
|
49
55
|
|
50
56
|
def queue_time_ms
|
51
57
|
scheduled = task.current_attempt_scheduled_time.to_f
|
@@ -54,24 +60,31 @@ module Temporal
|
|
54
60
|
end
|
55
61
|
|
56
62
|
def respond_completed(result)
|
57
|
-
Temporal.logger.info("Activity
|
58
|
-
|
63
|
+
Temporal.logger.info("Activity task completed", metadata.to_h)
|
64
|
+
log_retry = proc do
|
65
|
+
Temporal.logger.debug("Failed to report activity task completion, retrying", metadata.to_h)
|
66
|
+
end
|
67
|
+
Temporal::Client::Retryer.with_retries(on_retry: log_retry) do
|
68
|
+
client.respond_activity_task_completed(task_token: task_token, result: result)
|
69
|
+
end
|
59
70
|
rescue StandardError => error
|
60
|
-
Temporal.logger.error("Unable to complete Activity
|
71
|
+
Temporal.logger.error("Unable to complete Activity", metadata.to_h.merge(error: error.inspect))
|
72
|
+
|
73
|
+
Temporal::ErrorHandler.handle(error, metadata: metadata)
|
61
74
|
end
|
62
75
|
|
63
76
|
def respond_failed(error)
|
64
|
-
Temporal.logger.error("Activity
|
65
|
-
|
77
|
+
Temporal.logger.error("Activity task failed", metadata.to_h.merge(error: error.inspect))
|
78
|
+
log_retry = proc do
|
79
|
+
Temporal.logger.debug("Failed to report activity task failure, retrying", metadata.to_h)
|
80
|
+
end
|
81
|
+
Temporal::Client::Retryer.with_retries(on_retry: log_retry) do
|
82
|
+
client.respond_activity_task_failed(task_token: task_token, exception: error)
|
83
|
+
end
|
66
84
|
rescue StandardError => error
|
67
|
-
Temporal.logger.error("Unable to fail Activity
|
68
|
-
end
|
69
|
-
|
70
|
-
def parse_payload(payload)
|
71
|
-
return if payload.nil? || payload.payloads.empty?
|
85
|
+
Temporal.logger.error("Unable to fail Activity task", metadata.to_h.merge(error: error.inspect))
|
72
86
|
|
73
|
-
|
74
|
-
JSON.deserialize(binary)
|
87
|
+
Temporal::ErrorHandler.handle(error, metadata: metadata)
|
75
88
|
end
|
76
89
|
end
|
77
90
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Temporal
|
2
|
+
module Client
|
3
|
+
module Converter
|
4
|
+
class Base
|
5
|
+
def initialize(payload_converter:)
|
6
|
+
@payload_converter = payload_converter
|
7
|
+
end
|
8
|
+
|
9
|
+
def from_payloads(payloads)
|
10
|
+
return nil if payloads.nil?
|
11
|
+
payloads.payloads.map(&method(:from_payload))
|
12
|
+
end
|
13
|
+
|
14
|
+
def from_payload(payload)
|
15
|
+
payload_converter.from_payload(payload)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_payloads(data)
|
19
|
+
return nil if data.nil?
|
20
|
+
Temporal::Api::Common::V1::Payloads.new(
|
21
|
+
payloads: data.map(&method(:to_payload))
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_payload(data)
|
26
|
+
payload_converter.to_payload(data)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_reader :payload_converter
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'temporal/client/converter/base'
|
2
|
+
|
3
|
+
module Temporal
|
4
|
+
module Client
|
5
|
+
module Converter
|
6
|
+
class Composite < Base
|
7
|
+
class ConverterNotFound < RuntimeError; end
|
8
|
+
class MetadataNotSet < RuntimeError; end
|
9
|
+
|
10
|
+
def initialize(payload_converters:)
|
11
|
+
@payload_converters = payload_converters
|
12
|
+
@payload_converters_by_encoding = {}
|
13
|
+
|
14
|
+
@payload_converters.each do |converter|
|
15
|
+
@payload_converters_by_encoding[converter.encoding] = converter
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def from_payload(payload)
|
20
|
+
encoding = payload.metadata['encoding']
|
21
|
+
if encoding.nil?
|
22
|
+
raise MetadataNotSet
|
23
|
+
end
|
24
|
+
|
25
|
+
converter = payload_converters_by_encoding[encoding]
|
26
|
+
|
27
|
+
if converter.nil?
|
28
|
+
raise ConverterNotFound
|
29
|
+
end
|
30
|
+
|
31
|
+
converter.from_payload(payload)
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_payload(data)
|
35
|
+
payload_converters.each do |converter|
|
36
|
+
payload = converter.to_payload(data)
|
37
|
+
return payload unless payload.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
raise ConverterNotFound
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
attr_reader :payload_converters, :payload_converters_by_encoding
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'temporal/json'
|
2
|
+
|
3
|
+
module Temporal
|
4
|
+
module Client
|
5
|
+
module Converter
|
6
|
+
module Payload
|
7
|
+
class Bytes
|
8
|
+
ENCODING = 'binary/plain'.freeze
|
9
|
+
|
10
|
+
def encoding
|
11
|
+
ENCODING
|
12
|
+
end
|
13
|
+
|
14
|
+
def from_payload(payload)
|
15
|
+
payload.data
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_payload(data)
|
19
|
+
return nil unless data.is_a?(String) && data.encoding == Encoding::ASCII_8BIT
|
20
|
+
|
21
|
+
Temporal::Api::Common::V1::Payload.new(
|
22
|
+
metadata: { 'encoding' => ENCODING },
|
23
|
+
data: data
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'temporal/json'
|
2
|
+
|
3
|
+
module Temporal
|
4
|
+
module Client
|
5
|
+
module Converter
|
6
|
+
module Payload
|
7
|
+
class JSON
|
8
|
+
ENCODING = 'json/plain'.freeze
|
9
|
+
|
10
|
+
def encoding
|
11
|
+
ENCODING
|
12
|
+
end
|
13
|
+
|
14
|
+
def from_payload(payload)
|
15
|
+
Temporal::JSON.deserialize(payload.data)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_payload(data)
|
19
|
+
Temporal::Api::Common::V1::Payload.new(
|
20
|
+
metadata: { 'encoding' => ENCODING },
|
21
|
+
data: Temporal::JSON.serialize(data).b
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Temporal
|
2
|
+
module Client
|
3
|
+
module Converter
|
4
|
+
module Payload
|
5
|
+
class Nil
|
6
|
+
ENCODING = 'binary/null'.freeze
|
7
|
+
|
8
|
+
def encoding
|
9
|
+
ENCODING
|
10
|
+
end
|
11
|
+
|
12
|
+
def from_payload(payload)
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_payload(data)
|
17
|
+
return nil unless data.nil?
|
18
|
+
|
19
|
+
Temporal::Api::Common::V1::Payload.new(
|
20
|
+
metadata: { 'encoding' => ENCODING }
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,30 +1,39 @@
|
|
1
1
|
require 'grpc'
|
2
2
|
require 'google/protobuf/well_known_types'
|
3
3
|
require 'securerandom'
|
4
|
-
require 'temporal/json'
|
5
4
|
require 'temporal/client/errors'
|
6
5
|
require 'temporal/client/serializer'
|
7
|
-
require 'temporal/client/serializer/payload'
|
8
6
|
require 'temporal/client/serializer/failure'
|
9
7
|
require 'gen/temporal/api/workflowservice/v1/service_services_pb'
|
8
|
+
require 'temporal/concerns/payloads'
|
10
9
|
|
11
10
|
module Temporal
|
12
11
|
module Client
|
13
12
|
class GRPCClient
|
13
|
+
include Concerns::Payloads
|
14
|
+
|
14
15
|
WORKFLOW_ID_REUSE_POLICY = {
|
15
16
|
allow_failed: Temporal::Api::Enums::V1::WorkflowIdReusePolicy::WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE_FAILED_ONLY,
|
16
17
|
allow: Temporal::Api::Enums::V1::WorkflowIdReusePolicy::WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE,
|
17
18
|
reject: Temporal::Api::Enums::V1::WorkflowIdReusePolicy::WORKFLOW_ID_REUSE_POLICY_REJECT_DUPLICATE
|
18
19
|
}.freeze
|
19
20
|
|
21
|
+
HISTORY_EVENT_FILTER = {
|
22
|
+
all: Temporal::Api::Enums::V1::HistoryEventFilterType::HISTORY_EVENT_FILTER_TYPE_ALL_EVENT,
|
23
|
+
close: Temporal::Api::Enums::V1::HistoryEventFilterType::HISTORY_EVENT_FILTER_TYPE_CLOSE_EVENT,
|
24
|
+
}.freeze
|
25
|
+
|
20
26
|
def initialize(host, port, identity)
|
21
27
|
@url = "#{host}:#{port}"
|
22
28
|
@identity = identity
|
29
|
+
@poll = true
|
30
|
+
@poll_mutex = Mutex.new
|
31
|
+
@poll_request = nil
|
23
32
|
end
|
24
33
|
|
25
34
|
def register_namespace(name:, description: nil, global: false, retention_period: 10)
|
26
35
|
request = Temporal::Api::WorkflowService::V1::RegisterNamespaceRequest.new(
|
27
|
-
|
36
|
+
namespace: name,
|
28
37
|
description: description,
|
29
38
|
is_global_namespace: global,
|
30
39
|
workflow_execution_retention_period: Google::Protobuf::Duration.new(
|
@@ -37,7 +46,7 @@ module Temporal
|
|
37
46
|
end
|
38
47
|
|
39
48
|
def describe_namespace(name:)
|
40
|
-
request = Temporal::Api::WorkflowService::V1::DescribeNamespaceRequest.new(
|
49
|
+
request = Temporal::Api::WorkflowService::V1::DescribeNamespaceRequest.new(namespace: name)
|
41
50
|
client.describe_namespace(request)
|
42
51
|
end
|
43
52
|
|
@@ -48,7 +57,7 @@ module Temporal
|
|
48
57
|
|
49
58
|
def update_namespace(name:, description:)
|
50
59
|
request = Temporal::Api::WorkflowService::V1::UpdateNamespaceRequest.new(
|
51
|
-
|
60
|
+
namespace: name,
|
52
61
|
update_info: Temporal::Api::WorkflowService::V1::UpdateNamespaceInfo.new(
|
53
62
|
description: description
|
54
63
|
)
|
@@ -57,7 +66,7 @@ module Temporal
|
|
57
66
|
end
|
58
67
|
|
59
68
|
def deprecate_namespace(name:)
|
60
|
-
request = Temporal::Api::WorkflowService::V1::DeprecateNamespaceRequest.new(
|
69
|
+
request = Temporal::Api::WorkflowService::V1::DeprecateNamespaceRequest.new(namespace: name)
|
61
70
|
client.deprecate_namespace(request)
|
62
71
|
end
|
63
72
|
|
@@ -68,9 +77,11 @@ module Temporal
|
|
68
77
|
task_queue:,
|
69
78
|
input: nil,
|
70
79
|
execution_timeout:,
|
80
|
+
run_timeout:,
|
71
81
|
task_timeout:,
|
72
82
|
workflow_id_reuse_policy: nil,
|
73
|
-
headers: nil
|
83
|
+
headers: nil,
|
84
|
+
cron_schedule: nil
|
74
85
|
)
|
75
86
|
request = Temporal::Api::WorkflowService::V1::StartWorkflowExecutionRequest.new(
|
76
87
|
identity: identity,
|
@@ -82,14 +93,15 @@ module Temporal
|
|
82
93
|
task_queue: Temporal::Api::TaskQueue::V1::TaskQueue.new(
|
83
94
|
name: task_queue
|
84
95
|
),
|
85
|
-
input:
|
96
|
+
input: to_payloads(input),
|
86
97
|
workflow_execution_timeout: execution_timeout,
|
87
|
-
workflow_run_timeout:
|
98
|
+
workflow_run_timeout: run_timeout,
|
88
99
|
workflow_task_timeout: task_timeout,
|
89
100
|
request_id: SecureRandom.uuid,
|
90
101
|
header: Temporal::Api::Common::V1::Header.new(
|
91
102
|
fields: headers
|
92
|
-
)
|
103
|
+
),
|
104
|
+
cron_schedule: cron_schedule
|
93
105
|
)
|
94
106
|
|
95
107
|
if workflow_id_reuse_policy
|
@@ -102,20 +114,43 @@ module Temporal
|
|
102
114
|
client.start_workflow_execution(request)
|
103
115
|
rescue GRPC::AlreadyExists => e
|
104
116
|
# Feel like there should be cleaner way to do this...
|
105
|
-
run_id = e.details[/RunId: (
|
117
|
+
run_id = e.details[/RunId: ([a-f0-9]+-[a-f0-9]+-[a-f0-9]+-[a-f0-9]+-[a-f0-9]+)/, 1]
|
106
118
|
raise Temporal::WorkflowExecutionAlreadyStartedFailure.new(e.details, run_id)
|
107
119
|
end
|
108
120
|
|
109
|
-
|
121
|
+
SERVER_MAX_GET_WORKFLOW_EXECUTION_HISTORY_POLL = 30
|
122
|
+
|
123
|
+
def get_workflow_execution_history(
|
124
|
+
namespace:,
|
125
|
+
workflow_id:,
|
126
|
+
run_id:,
|
127
|
+
next_page_token: nil,
|
128
|
+
wait_for_new_event: false,
|
129
|
+
event_type: :all,
|
130
|
+
timeout: nil
|
131
|
+
)
|
132
|
+
if wait_for_new_event
|
133
|
+
if timeout.nil?
|
134
|
+
# This is an internal error. Wrappers should enforce this.
|
135
|
+
raise "You must specify a timeout when wait_for_new_event = true."
|
136
|
+
elsif timeout > SERVER_MAX_GET_WORKFLOW_EXECUTION_HISTORY_POLL
|
137
|
+
raise ClientError.new(
|
138
|
+
"You may not specify a timeout of more than #{SERVER_MAX_GET_WORKFLOW_EXECUTION_HISTORY_POLL} seconds, got: #{timeout}."
|
139
|
+
)
|
140
|
+
end
|
141
|
+
end
|
110
142
|
request = Temporal::Api::WorkflowService::V1::GetWorkflowExecutionHistoryRequest.new(
|
111
143
|
namespace: namespace,
|
112
144
|
execution: Temporal::Api::Common::V1::WorkflowExecution.new(
|
113
145
|
workflow_id: workflow_id,
|
114
146
|
run_id: run_id
|
115
|
-
)
|
147
|
+
),
|
148
|
+
next_page_token: next_page_token,
|
149
|
+
wait_new_event: wait_for_new_event,
|
150
|
+
history_event_filter_type: HISTORY_EVENT_FILTER[event_type]
|
116
151
|
)
|
117
|
-
|
118
|
-
client.get_workflow_execution_history(request)
|
152
|
+
deadline = timeout ? Time.now + timeout : nil
|
153
|
+
client.get_workflow_execution_history(request, deadline: deadline)
|
119
154
|
end
|
120
155
|
|
121
156
|
def poll_workflow_task_queue(namespace:, task_queue:)
|
@@ -126,7 +161,13 @@ module Temporal
|
|
126
161
|
name: task_queue
|
127
162
|
)
|
128
163
|
)
|
129
|
-
|
164
|
+
|
165
|
+
poll_mutex.synchronize do
|
166
|
+
return unless can_poll?
|
167
|
+
@poll_request = client.poll_workflow_task_queue(request, return_op: true)
|
168
|
+
end
|
169
|
+
|
170
|
+
poll_request.execute
|
130
171
|
end
|
131
172
|
|
132
173
|
def respond_workflow_task_completed(task_token:, commands:)
|
@@ -156,13 +197,19 @@ module Temporal
|
|
156
197
|
name: task_queue
|
157
198
|
)
|
158
199
|
)
|
159
|
-
|
200
|
+
|
201
|
+
poll_mutex.synchronize do
|
202
|
+
return unless can_poll?
|
203
|
+
@poll_request = client.poll_activity_task_queue(request, return_op: true)
|
204
|
+
end
|
205
|
+
|
206
|
+
poll_request.execute
|
160
207
|
end
|
161
208
|
|
162
209
|
def record_activity_task_heartbeat(task_token:, details: nil)
|
163
210
|
request = Temporal::Api::WorkflowService::V1::RecordActivityTaskHeartbeatRequest.new(
|
164
211
|
task_token: task_token,
|
165
|
-
details:
|
212
|
+
details: to_details_payloads(details),
|
166
213
|
identity: identity
|
167
214
|
)
|
168
215
|
client.record_activity_task_heartbeat(request)
|
@@ -176,7 +223,7 @@ module Temporal
|
|
176
223
|
request = Temporal::Api::WorkflowService::V1::RespondActivityTaskCompletedRequest.new(
|
177
224
|
identity: identity,
|
178
225
|
task_token: task_token,
|
179
|
-
result:
|
226
|
+
result: to_result_payloads(result),
|
180
227
|
)
|
181
228
|
client.respond_activity_task_completed(request)
|
182
229
|
end
|
@@ -188,7 +235,7 @@ module Temporal
|
|
188
235
|
workflow_id: workflow_id,
|
189
236
|
run_id: run_id,
|
190
237
|
activity_id: activity_id,
|
191
|
-
result:
|
238
|
+
result: to_result_payloads(result)
|
192
239
|
)
|
193
240
|
client.respond_activity_task_completed_by_id(request)
|
194
241
|
end
|
@@ -217,7 +264,7 @@ module Temporal
|
|
217
264
|
def respond_activity_task_canceled(task_token:, details: nil)
|
218
265
|
request = Temporal::Api::WorkflowService::V1::RespondActivityTaskCanceledRequest.new(
|
219
266
|
task_token: task_token,
|
220
|
-
details:
|
267
|
+
details: to_details_payloads(details),
|
221
268
|
identity: identity
|
222
269
|
)
|
223
270
|
client.respond_activity_task_canceled(request)
|
@@ -239,7 +286,7 @@ module Temporal
|
|
239
286
|
run_id: run_id
|
240
287
|
),
|
241
288
|
signal_name: signal,
|
242
|
-
input:
|
289
|
+
input: to_signal_payloads(input),
|
243
290
|
identity: identity
|
244
291
|
)
|
245
292
|
client.signal_workflow_execution(request)
|
@@ -254,7 +301,7 @@ module Temporal
|
|
254
301
|
namespace: namespace,
|
255
302
|
workflow_execution: Temporal::Api::Common::V1::WorkflowExecution.new(
|
256
303
|
workflow_id: workflow_id,
|
257
|
-
run_id: run_id
|
304
|
+
run_id: run_id,
|
258
305
|
),
|
259
306
|
reason: reason,
|
260
307
|
workflow_task_finish_event_id: workflow_task_event_id
|
@@ -262,8 +309,25 @@ module Temporal
|
|
262
309
|
client.reset_workflow_execution(request)
|
263
310
|
end
|
264
311
|
|
265
|
-
def terminate_workflow_execution
|
266
|
-
|
312
|
+
def terminate_workflow_execution(
|
313
|
+
namespace:,
|
314
|
+
workflow_id:,
|
315
|
+
run_id:,
|
316
|
+
reason: nil,
|
317
|
+
details: nil
|
318
|
+
)
|
319
|
+
request = Temporal::Api::WorkflowService::V1::TerminateWorkflowExecutionRequest.new(
|
320
|
+
identity: identity,
|
321
|
+
namespace: namespace,
|
322
|
+
workflow_execution: Temporal::Api::Common::V1::WorkflowExecution.new(
|
323
|
+
workflow_id: workflow_id,
|
324
|
+
run_id: run_id,
|
325
|
+
),
|
326
|
+
reason: reason,
|
327
|
+
details: to_details_payloads(details)
|
328
|
+
)
|
329
|
+
|
330
|
+
client.terminate_workflow_execution(request)
|
267
331
|
end
|
268
332
|
|
269
333
|
def list_open_workflow_executions
|
@@ -329,17 +393,28 @@ module Temporal
|
|
329
393
|
client.describe_task_queue(request)
|
330
394
|
end
|
331
395
|
|
396
|
+
def cancel_polling_request
|
397
|
+
poll_mutex.synchronize do
|
398
|
+
@poll = false
|
399
|
+
poll_request&.cancel
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
332
403
|
private
|
333
404
|
|
334
|
-
attr_reader :url, :identity
|
405
|
+
attr_reader :url, :identity, :poll_mutex, :poll_request
|
335
406
|
|
336
407
|
def client
|
337
408
|
@client ||= Temporal::Api::WorkflowService::V1::WorkflowService::Stub.new(
|
338
409
|
url,
|
339
410
|
:this_channel_is_insecure,
|
340
|
-
timeout:
|
411
|
+
timeout: 60
|
341
412
|
)
|
342
413
|
end
|
414
|
+
|
415
|
+
def can_poll?
|
416
|
+
@poll
|
417
|
+
end
|
343
418
|
end
|
344
419
|
end
|
345
420
|
end
|