temporalio 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/Cargo.lock +659 -370
  4. data/Cargo.toml +2 -2
  5. data/Gemfile +3 -3
  6. data/README.md +589 -47
  7. data/Rakefile +10 -296
  8. data/ext/Cargo.toml +1 -0
  9. data/lib/temporalio/activity/complete_async_error.rb +1 -1
  10. data/lib/temporalio/activity/context.rb +5 -2
  11. data/lib/temporalio/activity/definition.rb +163 -65
  12. data/lib/temporalio/activity/info.rb +22 -21
  13. data/lib/temporalio/activity.rb +2 -59
  14. data/lib/temporalio/api/activity/v1/message.rb +25 -0
  15. data/lib/temporalio/api/cloud/account/v1/message.rb +28 -0
  16. data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +34 -1
  17. data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +1 -1
  18. data/lib/temporalio/api/cloud/identity/v1/message.rb +6 -1
  19. data/lib/temporalio/api/cloud/namespace/v1/message.rb +8 -1
  20. data/lib/temporalio/api/cloud/nexus/v1/message.rb +31 -0
  21. data/lib/temporalio/api/cloud/operation/v1/message.rb +2 -1
  22. data/lib/temporalio/api/cloud/region/v1/message.rb +2 -1
  23. data/lib/temporalio/api/cloud/resource/v1/message.rb +23 -0
  24. data/lib/temporalio/api/cloud/sink/v1/message.rb +24 -0
  25. data/lib/temporalio/api/cloud/usage/v1/message.rb +31 -0
  26. data/lib/temporalio/api/common/v1/message.rb +7 -1
  27. data/lib/temporalio/api/enums/v1/event_type.rb +1 -1
  28. data/lib/temporalio/api/enums/v1/failed_cause.rb +1 -1
  29. data/lib/temporalio/api/enums/v1/reset.rb +1 -1
  30. data/lib/temporalio/api/history/v1/message.rb +1 -1
  31. data/lib/temporalio/api/nexus/v1/message.rb +2 -2
  32. data/lib/temporalio/api/operatorservice/v1/service.rb +1 -1
  33. data/lib/temporalio/api/payload_visitor.rb +1513 -0
  34. data/lib/temporalio/api/schedule/v1/message.rb +2 -1
  35. data/lib/temporalio/api/testservice/v1/request_response.rb +31 -0
  36. data/lib/temporalio/api/testservice/v1/service.rb +23 -0
  37. data/lib/temporalio/api/workflow/v1/message.rb +1 -1
  38. data/lib/temporalio/api/workflowservice/v1/request_response.rb +17 -2
  39. data/lib/temporalio/api/workflowservice/v1/service.rb +1 -1
  40. data/lib/temporalio/api.rb +1 -0
  41. data/lib/temporalio/cancellation.rb +34 -14
  42. data/lib/temporalio/client/async_activity_handle.rb +12 -37
  43. data/lib/temporalio/client/connection/cloud_service.rb +309 -231
  44. data/lib/temporalio/client/connection/operator_service.rb +36 -84
  45. data/lib/temporalio/client/connection/service.rb +6 -5
  46. data/lib/temporalio/client/connection/test_service.rb +111 -0
  47. data/lib/temporalio/client/connection/workflow_service.rb +264 -441
  48. data/lib/temporalio/client/connection.rb +90 -44
  49. data/lib/temporalio/client/interceptor.rb +160 -60
  50. data/lib/temporalio/client/schedule.rb +967 -0
  51. data/lib/temporalio/client/schedule_handle.rb +126 -0
  52. data/lib/temporalio/client/workflow_execution.rb +7 -10
  53. data/lib/temporalio/client/workflow_handle.rb +38 -95
  54. data/lib/temporalio/client/workflow_update_handle.rb +3 -5
  55. data/lib/temporalio/client.rb +122 -42
  56. data/lib/temporalio/common_enums.rb +17 -0
  57. data/lib/temporalio/converters/data_converter.rb +4 -7
  58. data/lib/temporalio/converters/failure_converter.rb +5 -3
  59. data/lib/temporalio/converters/payload_converter/composite.rb +4 -0
  60. data/lib/temporalio/converters/payload_converter.rb +6 -8
  61. data/lib/temporalio/converters/raw_value.rb +20 -0
  62. data/lib/temporalio/error/failure.rb +1 -1
  63. data/lib/temporalio/error.rb +10 -2
  64. data/lib/temporalio/internal/bridge/api/core_interface.rb +5 -1
  65. data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +33 -0
  66. data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +5 -1
  67. data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +4 -1
  68. data/lib/temporalio/internal/bridge/client.rb +11 -6
  69. data/lib/temporalio/internal/bridge/testing.rb +20 -0
  70. data/lib/temporalio/internal/bridge/worker.rb +2 -0
  71. data/lib/temporalio/internal/bridge.rb +1 -1
  72. data/lib/temporalio/internal/client/implementation.rb +245 -70
  73. data/lib/temporalio/internal/metric.rb +122 -0
  74. data/lib/temporalio/internal/proto_utils.rb +86 -7
  75. data/lib/temporalio/internal/worker/activity_worker.rb +52 -24
  76. data/lib/temporalio/internal/worker/multi_runner.rb +51 -7
  77. data/lib/temporalio/internal/worker/workflow_instance/child_workflow_handle.rb +54 -0
  78. data/lib/temporalio/internal/worker/workflow_instance/context.rb +329 -0
  79. data/lib/temporalio/internal/worker/workflow_instance/details.rb +44 -0
  80. data/lib/temporalio/internal/worker/workflow_instance/external_workflow_handle.rb +32 -0
  81. data/lib/temporalio/internal/worker/workflow_instance/externally_immutable_hash.rb +22 -0
  82. data/lib/temporalio/internal/worker/workflow_instance/handler_execution.rb +25 -0
  83. data/lib/temporalio/internal/worker/workflow_instance/handler_hash.rb +41 -0
  84. data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +97 -0
  85. data/lib/temporalio/internal/worker/workflow_instance/inbound_implementation.rb +62 -0
  86. data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +415 -0
  87. data/lib/temporalio/internal/worker/workflow_instance/replay_safe_logger.rb +37 -0
  88. data/lib/temporalio/internal/worker/workflow_instance/replay_safe_metric.rb +40 -0
  89. data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +163 -0
  90. data/lib/temporalio/internal/worker/workflow_instance.rb +730 -0
  91. data/lib/temporalio/internal/worker/workflow_worker.rb +196 -0
  92. data/lib/temporalio/metric.rb +109 -0
  93. data/lib/temporalio/retry_policy.rb +37 -14
  94. data/lib/temporalio/runtime.rb +118 -75
  95. data/lib/temporalio/search_attributes.rb +80 -37
  96. data/lib/temporalio/testing/activity_environment.rb +2 -2
  97. data/lib/temporalio/testing/workflow_environment.rb +251 -5
  98. data/lib/temporalio/version.rb +1 -1
  99. data/lib/temporalio/worker/activity_executor/thread_pool.rb +9 -217
  100. data/lib/temporalio/worker/activity_executor.rb +3 -3
  101. data/lib/temporalio/worker/interceptor.rb +340 -66
  102. data/lib/temporalio/worker/thread_pool.rb +237 -0
  103. data/lib/temporalio/worker/workflow_executor/thread_pool.rb +230 -0
  104. data/lib/temporalio/worker/workflow_executor.rb +26 -0
  105. data/lib/temporalio/worker.rb +201 -30
  106. data/lib/temporalio/workflow/activity_cancellation_type.rb +20 -0
  107. data/lib/temporalio/workflow/child_workflow_cancellation_type.rb +21 -0
  108. data/lib/temporalio/workflow/child_workflow_handle.rb +43 -0
  109. data/lib/temporalio/workflow/definition.rb +566 -0
  110. data/lib/temporalio/workflow/external_workflow_handle.rb +41 -0
  111. data/lib/temporalio/workflow/future.rb +151 -0
  112. data/lib/temporalio/workflow/handler_unfinished_policy.rb +13 -0
  113. data/lib/temporalio/workflow/info.rb +82 -0
  114. data/lib/temporalio/workflow/parent_close_policy.rb +19 -0
  115. data/lib/temporalio/workflow/update_info.rb +20 -0
  116. data/lib/temporalio/workflow.rb +523 -0
  117. data/lib/temporalio.rb +4 -0
  118. data/temporalio.gemspec +2 -2
  119. metadata +50 -8
@@ -1,54 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Much of this logic taken from
4
- # https://github.com/ruby-concurrency/concurrent-ruby/blob/044020f44b36930b863b930f3ee8fa1e9f750469/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb,
5
- # see MIT license at
6
- # https://github.com/ruby-concurrency/concurrent-ruby/blob/044020f44b36930b863b930f3ee8fa1e9f750469/LICENSE.txt
3
+ require 'temporalio/worker/thread_pool'
7
4
 
8
5
  module Temporalio
9
6
  class Worker
10
7
  class ActivityExecutor
11
- # Activity executor for scheduling activities in their own thread. This implementation is a stripped down form of
12
- # Concurrent Ruby's `CachedThreadPool`.
8
+ # Activity executor for scheduling activities in their own thread using {Worker::ThreadPool}.
13
9
  class ThreadPool < ActivityExecutor
14
- # @return [ThreadPool] Default/shared thread pool executor instance with unlimited max threads.
10
+ # @return [ThreadPool] Default/shared thread pool executor using default thread pool.
15
11
  def self.default
16
12
  @default ||= new
17
13
  end
18
14
 
19
- # @!visibility private
20
- def self._monotonic_time
21
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
22
- end
23
-
24
- # Create a new thread pool executor that creates threads as needed.
15
+ # Create a new thread pool executor.
25
16
  #
26
- # @param max_threads [Integer, nil] Maximum number of thread workers to create, or nil for unlimited max.
27
- # @param idle_timeout [Float] Number of seconds before a thread worker with no work should be stopped. Note,
28
- # the check of whether a thread worker is idle is only done on each new activity.
29
- def initialize(max_threads: nil, idle_timeout: 20) # rubocop:disable Lint/MissingSuper
30
- @max_threads = max_threads
31
- @idle_timeout = idle_timeout
32
-
33
- @mutex = Mutex.new
34
- @pool = []
35
- @ready = []
36
- @queue = []
37
- @scheduled_task_count = 0
38
- @completed_task_count = 0
39
- @largest_length = 0
40
- @workers_counter = 0
41
- @prune_interval = @idle_timeout / 2
42
- @next_prune_time = ThreadPool._monotonic_time + @prune_interval
17
+ # @param thread_pool [Worker::ThreadPool] Thread pool to use.
18
+ def initialize(thread_pool = Worker::ThreadPool.default) # rubocop:disable Lint/MissingSuper
19
+ @thread_pool = thread_pool
43
20
  end
44
21
 
45
22
  # @see ActivityExecutor.execute_activity
46
- def execute_activity(_defn, &block)
47
- @mutex.synchronize do
48
- locked_assign_worker(&block) || locked_enqueue(&block)
49
- @scheduled_task_count += 1
50
- locked_prune_pool if @next_prune_time < ThreadPool._monotonic_time
51
- end
23
+ def execute_activity(_defn, &)
24
+ @thread_pool.execute(&)
52
25
  end
53
26
 
54
27
  # @see ActivityExecutor.activity_context
@@ -67,187 +40,6 @@ module Temporalio
67
40
  thread.raise(Error::CanceledError.new('Activity canceled')) if thread[:temporal_activity_context] == context
68
41
  end
69
42
  end
70
-
71
- # @return [Integer] The largest number of threads that have been created in the pool since construction.
72
- def largest_length
73
- @mutex.synchronize { @largest_length }
74
- end
75
-
76
- # @return [Integer] The number of tasks that have been scheduled for execution on the pool since construction.
77
- def scheduled_task_count
78
- @mutex.synchronize { @scheduled_task_count }
79
- end
80
-
81
- # @return [Integer] The number of tasks that have been completed by the pool since construction.
82
- def completed_task_count
83
- @mutex.synchronize { @completed_task_count }
84
- end
85
-
86
- # @return [Integer] The number of threads that are actively executing tasks.
87
- def active_count
88
- @mutex.synchronize { @pool.length - @ready.length }
89
- end
90
-
91
- # @return [Integer] The number of threads currently in the pool.
92
- def length
93
- @mutex.synchronize { @pool.length }
94
- end
95
-
96
- # @return [Integer] The number of tasks in the queue awaiting execution.
97
- def queue_length
98
- @mutex.synchronize { @queue.length }
99
- end
100
-
101
- # Gracefully shutdown each thread when it is done with its current task. This should not be called until all
102
- # workers using this executor are complete. This does not need to be called at all on program exit (e.g. for the
103
- # global default).
104
- def shutdown
105
- @mutex.synchronize do
106
- # Stop all workers
107
- @pool.each(&:stop)
108
- end
109
- end
110
-
111
- # Kill each thread. This should not be called until all workers using this executor are complete. This does not
112
- # need to be called at all on program exit (e.g. for the global default).
113
- def kill
114
- @mutex.synchronize do
115
- # Kill all workers
116
- @pool.each(&:kill)
117
- @pool.clear
118
- @ready.clear
119
- end
120
- end
121
-
122
- # @!visibility private
123
- def _remove_busy_worker(worker)
124
- @mutex.synchronize { locked_remove_busy_worker(worker) }
125
- end
126
-
127
- # @!visibility private
128
- def _ready_worker(worker, last_message)
129
- @mutex.synchronize { locked_ready_worker(worker, last_message) }
130
- end
131
-
132
- # @!visibility private
133
- def _worker_died(worker)
134
- @mutex.synchronize { locked_worker_died(worker) }
135
- end
136
-
137
- # @!visibility private
138
- def _worker_task_completed
139
- @mutex.synchronize { @completed_task_count += 1 }
140
- end
141
-
142
- private
143
-
144
- def locked_assign_worker(&block)
145
- # keep growing if the pool is not at the minimum yet
146
- worker, = @ready.pop || locked_add_busy_worker
147
- if worker
148
- worker << block
149
- true
150
- else
151
- false
152
- end
153
- end
154
-
155
- def locked_enqueue(&block)
156
- @queue << block
157
- end
158
-
159
- def locked_add_busy_worker
160
- return if @max_threads && @pool.size >= @max_threads
161
-
162
- @workers_counter += 1
163
- @pool << (worker = Worker.new(self, @workers_counter))
164
- @largest_length = @pool.length if @pool.length > @largest_length
165
- worker
166
- end
167
-
168
- def locked_prune_pool
169
- now = ThreadPool._monotonic_time
170
- stopped_workers = 0
171
- while !@ready.empty? && (@pool.size - stopped_workers).positive?
172
- worker, last_message = @ready.first
173
- break unless now - last_message > @idle_timeout
174
-
175
- stopped_workers += 1
176
- @ready.shift
177
- worker << :stop
178
-
179
- end
180
-
181
- @next_prune_time = ThreadPool._monotonic_time + @prune_interval
182
- end
183
-
184
- def locked_remove_busy_worker(worker)
185
- @pool.delete(worker)
186
- end
187
-
188
- def locked_ready_worker(worker, last_message)
189
- block = @queue.shift
190
- if block
191
- worker << block
192
- else
193
- @ready.push([worker, last_message])
194
- end
195
- end
196
-
197
- def locked_worker_died(worker)
198
- locked_remove_busy_worker(worker)
199
- replacement_worker = locked_add_busy_worker
200
- locked_ready_worker(replacement_worker, ThreadPool._monotonic_time) if replacement_worker
201
- end
202
-
203
- # @!visibility private
204
- class Worker
205
- def initialize(pool, id)
206
- @queue = Queue.new
207
- @thread = Thread.new(@queue, pool) do |my_queue, my_pool|
208
- catch(:stop) do
209
- loop do
210
- case block = my_queue.pop
211
- when :stop
212
- pool._remove_busy_worker(self)
213
- throw :stop
214
- else
215
- begin
216
- block.call
217
- my_pool._worker_task_completed
218
- my_pool._ready_worker(self, ThreadPool._monotonic_time)
219
- rescue StandardError => e
220
- # Ignore
221
- warn("Unexpected activity block error: #{e}")
222
- rescue Exception => e # rubocop:disable Lint/RescueException
223
- warn("Unexpected activity block exception: #{e}")
224
- my_pool._worker_died(self)
225
- throw :stop
226
- end
227
- end
228
- end
229
- end
230
- end
231
- @thread.name = "activity-thread-#{id}"
232
- end
233
-
234
- # @!visibility private
235
- def <<(block)
236
- @queue << block
237
- end
238
-
239
- # @!visibility private
240
- def stop
241
- @queue << :stop
242
- end
243
-
244
- # @!visibility private
245
- def kill
246
- @thread.kill
247
- end
248
- end
249
-
250
- private_constant :Worker
251
43
  end
252
44
  end
253
45
  end
@@ -21,7 +21,7 @@ module Temporalio
21
21
  # allows executor implementations to do eager validation based on the definition. This does not have to be
22
22
  # implemented and the default is a no-op.
23
23
  #
24
- # @param defn [Activity::Definition] Activity definition.
24
+ # @param defn [Activity::Definition::Info] Activity definition info.
25
25
  def initialize_activity(defn)
26
26
  # Default no-op
27
27
  end
@@ -29,7 +29,7 @@ module Temporalio
29
29
  # Execute the given block in the executor. The block is built to never raise and need no arguments. Implementers
30
30
  # must implement this.
31
31
  #
32
- # @param defn [Activity::Definition] Activity definition.
32
+ # @param defn [Activity::Definition::Info] Activity definition info.
33
33
  # @yield Block to execute.
34
34
  def execute_activity(defn, &)
35
35
  raise NotImplementedError
@@ -45,7 +45,7 @@ module Temporalio
45
45
  # {execute_activity} with a context before user code is executed and with nil after user code is complete.
46
46
  # Implementers must implement this.
47
47
  #
48
- # @param defn [Activity::Definition] Activity definition.
48
+ # @param defn [Activity::Definition::Info] Activity definition info.
49
49
  # @param context [Activity::Context, nil] The value to set.
50
50
  def set_activity_context(defn, context)
51
51
  raise NotImplementedError