temporalio 0.0.2 → 0.1.0
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/README.md +25 -23
- data/bridge/Cargo.lock +168 -59
- data/bridge/Cargo.toml +4 -2
- data/bridge/sdk-core/README.md +19 -6
- data/bridge/sdk-core/client/src/lib.rs +215 -39
- data/bridge/sdk-core/client/src/metrics.rs +17 -8
- data/bridge/sdk-core/client/src/raw.rs +4 -4
- data/bridge/sdk-core/client/src/retry.rs +32 -20
- data/bridge/sdk-core/core/Cargo.toml +22 -9
- data/bridge/sdk-core/core/src/abstractions.rs +203 -14
- data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +76 -41
- data/bridge/sdk-core/core/src/core_tests/determinism.rs +165 -2
- data/bridge/sdk-core/core/src/core_tests/local_activities.rs +204 -83
- data/bridge/sdk-core/core/src/core_tests/queries.rs +3 -4
- data/bridge/sdk-core/core/src/core_tests/workers.rs +1 -3
- data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +397 -54
- data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +106 -12
- data/bridge/sdk-core/core/src/internal_flags.rs +136 -0
- data/bridge/sdk-core/core/src/lib.rs +16 -9
- data/bridge/sdk-core/core/src/telemetry/log_export.rs +1 -1
- data/bridge/sdk-core/core/src/telemetry/metrics.rs +69 -35
- data/bridge/sdk-core/core/src/telemetry/mod.rs +29 -13
- data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +17 -12
- data/bridge/sdk-core/core/src/test_help/mod.rs +62 -12
- data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +112 -156
- data/bridge/sdk-core/core/src/worker/activities/activity_task_poller_stream.rs +89 -0
- data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +352 -122
- data/bridge/sdk-core/core/src/worker/activities.rs +233 -157
- data/bridge/sdk-core/core/src/worker/client/mocks.rs +22 -2
- data/bridge/sdk-core/core/src/worker/client.rs +18 -2
- data/bridge/sdk-core/core/src/worker/mod.rs +165 -58
- data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +1 -3
- data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -5
- data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +856 -277
- data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +100 -43
- data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +7 -7
- data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +5 -4
- data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +87 -27
- data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +5 -4
- data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +5 -4
- data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +5 -4
- data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +137 -62
- data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +25 -17
- data/bridge/sdk-core/core/src/worker/workflow/machines/modify_workflow_properties_state_machine.rs +7 -6
- data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +103 -152
- data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +7 -7
- data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +9 -9
- data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +2 -2
- data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +14 -7
- data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +5 -16
- data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +201 -121
- data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +11 -14
- data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +30 -15
- data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +1026 -376
- data/bridge/sdk-core/core/src/worker/workflow/mod.rs +460 -384
- data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +40 -57
- data/bridge/sdk-core/core/src/worker/workflow/wft_extraction.rs +125 -0
- data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +1 -4
- data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/saved_wf_inputs.rs +117 -0
- data/bridge/sdk-core/core/src/worker/workflow/workflow_stream/tonic_status_serde.rs +24 -0
- data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +448 -718
- data/bridge/sdk-core/core-api/Cargo.toml +2 -1
- data/bridge/sdk-core/core-api/src/errors.rs +1 -34
- data/bridge/sdk-core/core-api/src/lib.rs +6 -2
- data/bridge/sdk-core/core-api/src/telemetry.rs +0 -6
- data/bridge/sdk-core/core-api/src/worker.rs +14 -1
- data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +18 -15
- data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +8 -3
- data/bridge/sdk-core/histories/evict_while_la_running_no_interference-16_history.bin +0 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +5 -17
- data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +11 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +1 -6
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +6 -6
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +5 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +22 -6
- data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +48 -19
- data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +2 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +3 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/{enums/v1/interaction_type.proto → protocol/v1/message.proto} +29 -11
- data/bridge/sdk-core/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +63 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +111 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +59 -28
- data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +2 -2
- data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +7 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +1 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +6 -0
- data/bridge/sdk-core/sdk/Cargo.toml +3 -2
- data/bridge/sdk-core/sdk/src/lib.rs +87 -20
- data/bridge/sdk-core/sdk/src/workflow_future.rs +9 -8
- data/bridge/sdk-core/sdk-core-protos/Cargo.toml +5 -2
- data/bridge/sdk-core/sdk-core-protos/build.rs +36 -1
- data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +100 -87
- data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +5 -1
- data/bridge/sdk-core/sdk-core-protos/src/lib.rs +175 -57
- data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +12 -2
- data/bridge/sdk-core/test-utils/Cargo.toml +3 -1
- data/bridge/sdk-core/test-utils/src/canned_histories.rs +106 -296
- data/bridge/sdk-core/test-utils/src/histfetch.rs +1 -1
- data/bridge/sdk-core/test-utils/src/lib.rs +82 -23
- data/bridge/sdk-core/test-utils/src/wf_input_saver.rs +50 -0
- data/bridge/sdk-core/test-utils/src/workflows.rs +29 -0
- data/bridge/sdk-core/tests/fuzzy_workflow.rs +130 -0
- data/bridge/sdk-core/tests/{load_tests.rs → heavy_tests.rs} +125 -51
- data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +25 -3
- data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +5 -3
- data/bridge/sdk-core/tests/integ_tests/metrics_tests.rs +218 -16
- data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +4 -47
- data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +5 -128
- data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +83 -25
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +93 -69
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +1 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +6 -13
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +1 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +6 -2
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +3 -10
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +72 -191
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +1 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +7 -28
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +12 -7
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +1 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +18 -14
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +6 -20
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +10 -21
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +6 -4
- data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +10 -11
- data/bridge/sdk-core/tests/main.rs +3 -13
- data/bridge/sdk-core/tests/runner.rs +75 -36
- data/bridge/sdk-core/tests/wf_input_replay.rs +32 -0
- data/bridge/src/connection.rs +41 -25
- data/bridge/src/lib.rs +269 -14
- data/bridge/src/runtime.rs +1 -1
- data/bridge/src/test_server.rs +153 -0
- data/bridge/src/worker.rs +89 -16
- data/lib/gen/temporal/api/command/v1/message_pb.rb +4 -18
- data/lib/gen/temporal/api/common/v1/message_pb.rb +4 -0
- data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +1 -3
- data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +3 -3
- data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +2 -0
- data/lib/gen/temporal/api/enums/v1/update_pb.rb +6 -4
- data/lib/gen/temporal/api/history/v1/message_pb.rb +27 -19
- data/lib/gen/temporal/api/namespace/v1/message_pb.rb +1 -0
- data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +3 -0
- data/lib/gen/temporal/api/protocol/v1/message_pb.rb +30 -0
- data/lib/gen/temporal/api/sdk/v1/task_complete_metadata_pb.rb +23 -0
- data/lib/gen/temporal/api/testservice/v1/request_response_pb.rb +49 -0
- data/lib/gen/temporal/api/testservice/v1/service_pb.rb +21 -0
- data/lib/gen/temporal/api/update/v1/message_pb.rb +72 -0
- data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +26 -16
- data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +13 -9
- data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +10 -6
- data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +13 -9
- data/lib/gen/temporal/sdk/core/common/common_pb.rb +7 -3
- data/lib/gen/temporal/sdk/core/core_interface_pb.rb +9 -3
- data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +7 -3
- data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +27 -21
- data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +28 -24
- data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +12 -5
- data/lib/temporalio/activity/context.rb +13 -8
- data/lib/temporalio/activity/info.rb +1 -1
- data/lib/temporalio/bridge/connect_options.rb +15 -0
- data/lib/temporalio/bridge/retry_config.rb +24 -0
- data/lib/temporalio/bridge/tls_options.rb +19 -0
- data/lib/temporalio/client/implementation.rb +8 -8
- data/lib/temporalio/connection/retry_config.rb +44 -0
- data/lib/temporalio/connection/service.rb +20 -0
- data/lib/temporalio/connection/test_service.rb +92 -0
- data/lib/temporalio/connection/tls_options.rb +51 -0
- data/lib/temporalio/connection/workflow_service.rb +731 -0
- data/lib/temporalio/connection.rb +55 -720
- data/lib/temporalio/interceptor/activity_inbound.rb +22 -0
- data/lib/temporalio/interceptor/activity_outbound.rb +24 -0
- data/lib/temporalio/interceptor/chain.rb +5 -5
- data/lib/temporalio/interceptor/client.rb +8 -4
- data/lib/temporalio/interceptor.rb +22 -0
- data/lib/temporalio/retry_policy.rb +13 -3
- data/lib/temporalio/testing/time_skipping_handle.rb +32 -0
- data/lib/temporalio/testing/time_skipping_interceptor.rb +23 -0
- data/lib/temporalio/testing/workflow_environment.rb +112 -0
- data/lib/temporalio/testing.rb +175 -0
- data/lib/temporalio/version.rb +1 -1
- data/lib/temporalio/worker/activity_runner.rb +26 -4
- data/lib/temporalio/worker/activity_worker.rb +44 -18
- data/lib/temporalio/worker/sync_worker.rb +47 -11
- data/lib/temporalio/worker.rb +27 -21
- data/lib/temporalio/workflow/async.rb +46 -0
- data/lib/temporalio/workflow/future.rb +138 -0
- data/lib/temporalio/workflow/info.rb +76 -0
- data/temporalio.gemspec +4 -3
- metadata +67 -17
- data/bridge/sdk-core/Cargo.lock +0 -2606
- data/bridge/sdk-core/protos/api_upstream/temporal/api/interaction/v1/message.proto +0 -87
- data/lib/bridge.so +0 -0
- data/lib/gen/temporal/api/enums/v1/interaction_type_pb.rb +0 -25
- data/lib/gen/temporal/api/interaction/v1/message_pb.rb +0 -49
- data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +0 -222
|
@@ -1,17 +1,32 @@
|
|
|
1
1
|
require 'temporalio/error/failure'
|
|
2
2
|
require 'temporalio/errors'
|
|
3
|
+
require 'temporalio/interceptor'
|
|
4
|
+
require 'temporalio/interceptor/chain'
|
|
3
5
|
require 'temporalio/worker/activity_runner'
|
|
4
|
-
require 'temporalio/worker/sync_worker'
|
|
5
6
|
|
|
6
7
|
module Temporalio
|
|
7
8
|
class Worker
|
|
8
9
|
# @api private
|
|
9
10
|
class ActivityWorker
|
|
10
|
-
def initialize(
|
|
11
|
+
def initialize(
|
|
12
|
+
task_queue,
|
|
13
|
+
worker,
|
|
14
|
+
activities,
|
|
15
|
+
converter,
|
|
16
|
+
interceptors,
|
|
17
|
+
executor,
|
|
18
|
+
graceful_timeout
|
|
19
|
+
)
|
|
11
20
|
@task_queue = task_queue
|
|
12
|
-
@worker =
|
|
21
|
+
@worker = worker
|
|
13
22
|
@activities = prepare_activities(activities)
|
|
14
23
|
@converter = converter
|
|
24
|
+
@inbound_interceptors = Temporalio::Interceptor::Chain.new(
|
|
25
|
+
Temporalio::Interceptor.filter(interceptors, :activity_inbound),
|
|
26
|
+
)
|
|
27
|
+
@outbound_interceptors = Temporalio::Interceptor::Chain.new(
|
|
28
|
+
Temporalio::Interceptor.filter(interceptors, :activity_outbound),
|
|
29
|
+
)
|
|
15
30
|
@executor = executor
|
|
16
31
|
@graceful_timeout = graceful_timeout
|
|
17
32
|
@running_activities = {}
|
|
@@ -38,20 +53,21 @@ module Temporalio
|
|
|
38
53
|
rescue Temporalio::Bridge::Error::WorkerShutdown
|
|
39
54
|
# No need to re-raise this error, it's a part of a normal shutdown
|
|
40
55
|
ensure
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
56
|
+
outstanding_tasks.each(&:wait)
|
|
57
|
+
@cancelation_task&.wait
|
|
58
|
+
drain_queue.close
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def setup_graceful_shutdown_timer(reactor)
|
|
62
|
+
if graceful_timeout
|
|
63
|
+
reactor.async do |async_task|
|
|
64
|
+
@cancelation_task = async_task.async do
|
|
65
|
+
sleep graceful_timeout
|
|
66
|
+
@running_activities.each_value do |activity_runner|
|
|
67
|
+
activity_runner.cancel('Worker is shutting down', by_request: false)
|
|
49
68
|
end
|
|
50
69
|
end
|
|
51
|
-
|
|
52
|
-
outstanding_tasks.each(&:wait)
|
|
53
|
-
cancelation_task&.stop # all tasks completed, stop cancellations
|
|
54
|
-
drain_queue.close
|
|
70
|
+
end
|
|
55
71
|
end
|
|
56
72
|
end
|
|
57
73
|
|
|
@@ -61,8 +77,9 @@ module Temporalio
|
|
|
61
77
|
|
|
62
78
|
private
|
|
63
79
|
|
|
64
|
-
attr_reader :task_queue, :worker, :activities, :converter, :
|
|
65
|
-
:
|
|
80
|
+
attr_reader :task_queue, :worker, :activities, :converter, :inbound_interceptors,
|
|
81
|
+
:outbound_interceptors, :executor, :graceful_timeout, :running_activities,
|
|
82
|
+
:cancellations, :drain_queue
|
|
66
83
|
|
|
67
84
|
def prepare_activities(activities)
|
|
68
85
|
activities.each_with_object({}) do |activity, result|
|
|
@@ -91,7 +108,16 @@ module Temporalio
|
|
|
91
108
|
|
|
92
109
|
def run_activity(token, start)
|
|
93
110
|
activity_class = lookup_activity(start.activity_type)
|
|
94
|
-
runner = ActivityRunner.new(
|
|
111
|
+
runner = ActivityRunner.new(
|
|
112
|
+
activity_class,
|
|
113
|
+
start,
|
|
114
|
+
task_queue,
|
|
115
|
+
token,
|
|
116
|
+
worker,
|
|
117
|
+
converter,
|
|
118
|
+
inbound_interceptors,
|
|
119
|
+
outbound_interceptors,
|
|
120
|
+
)
|
|
95
121
|
running_activities[token] = runner
|
|
96
122
|
queue = Queue.new
|
|
97
123
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
require 'temporal/sdk/core/activity_task/activity_task_pb'
|
|
2
2
|
require 'temporal/sdk/core/core_interface_pb'
|
|
3
|
+
require 'temporal/sdk/core/workflow_activation/workflow_activation_pb'
|
|
4
|
+
require 'temporal/sdk/core/workflow_completion/workflow_completion_pb'
|
|
3
5
|
|
|
4
6
|
module Temporalio
|
|
5
7
|
class Worker
|
|
@@ -19,45 +21,71 @@ module Temporalio
|
|
|
19
21
|
def poll_activity_task
|
|
20
22
|
with_queue do |done|
|
|
21
23
|
core_worker.poll_activity_task do |task, error|
|
|
22
|
-
done.call(task &&
|
|
24
|
+
done.call(task && Temporalio::Bridge::Api::ActivityTask::ActivityTask.decode(task), error)
|
|
23
25
|
end
|
|
24
26
|
end
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
def complete_activity_task_with_success(task_token, payload)
|
|
28
|
-
result =
|
|
29
|
-
completed:
|
|
30
|
+
result = Temporalio::Bridge::Api::ActivityResult::ActivityExecutionResult.new(
|
|
31
|
+
completed: Temporalio::Bridge::Api::ActivityResult::Success.new(result: payload),
|
|
30
32
|
)
|
|
31
33
|
|
|
32
34
|
complete_activity_task(task_token, result)
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
def complete_activity_task_with_failure(task_token, failure)
|
|
36
|
-
result =
|
|
37
|
-
failed:
|
|
38
|
+
result = Temporalio::Bridge::Api::ActivityResult::ActivityExecutionResult.new(
|
|
39
|
+
failed: Temporalio::Bridge::Api::ActivityResult::Failure.new(failure: failure),
|
|
38
40
|
)
|
|
39
41
|
|
|
40
42
|
complete_activity_task(task_token, result)
|
|
41
43
|
end
|
|
42
44
|
|
|
43
45
|
def complete_activity_task_with_cancellation(task_token, failure)
|
|
44
|
-
result =
|
|
45
|
-
cancelled:
|
|
46
|
+
result = Temporalio::Bridge::Api::ActivityResult::ActivityExecutionResult.new(
|
|
47
|
+
cancelled: Temporalio::Bridge::Api::ActivityResult::Cancellation.new(failure: failure),
|
|
46
48
|
)
|
|
47
49
|
|
|
48
50
|
complete_activity_task(task_token, result)
|
|
49
51
|
end
|
|
50
52
|
|
|
51
53
|
def record_activity_heartbeat(task_token, payloads)
|
|
52
|
-
proto =
|
|
54
|
+
proto = Temporalio::Bridge::Api::CoreInterface::ActivityHeartbeat.new(
|
|
53
55
|
task_token: task_token,
|
|
54
56
|
details: payloads,
|
|
55
57
|
)
|
|
56
|
-
encoded_proto =
|
|
58
|
+
encoded_proto = Temporalio::Bridge::Api::CoreInterface::ActivityHeartbeat.encode(proto)
|
|
57
59
|
|
|
58
60
|
core_worker.record_activity_heartbeat(encoded_proto)
|
|
59
61
|
end
|
|
60
62
|
|
|
63
|
+
def poll_workflow_activation
|
|
64
|
+
with_queue do |done|
|
|
65
|
+
core_worker.poll_workflow_activation do |task, error|
|
|
66
|
+
done.call(task && Temporalio::Bridge::Api::WorkflowActivation::WorkflowActivation.decode(task), error)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def complete_workflow_activation_with_success(run_id, commands)
|
|
72
|
+
proto = Temporalio::Bridge::Api::WorkflowCompletion::WorkflowActivationCompletion.new(
|
|
73
|
+
run_id: run_id,
|
|
74
|
+
successful: Temporalio::Bridge::Api::WorkflowCompletion::Success.new(commands: commands),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
complete_workflow_activation(proto)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def complete_workflow_activation_with_failure(run_id, failure)
|
|
81
|
+
proto = Temporalio::Bridge::Api::WorkflowCompletion::WorkflowActivationCompletion.new(
|
|
82
|
+
run_id: run_id,
|
|
83
|
+
failed: Temporalio::Bridge::Api::WorkflowCompletion::Failure.new(failure: failure),
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
complete_workflow_activation(proto)
|
|
87
|
+
end
|
|
88
|
+
|
|
61
89
|
private
|
|
62
90
|
|
|
63
91
|
attr_reader :core_worker
|
|
@@ -73,16 +101,24 @@ module Temporalio
|
|
|
73
101
|
end
|
|
74
102
|
|
|
75
103
|
def complete_activity_task(task_token, result)
|
|
76
|
-
proto =
|
|
104
|
+
proto = Temporalio::Bridge::Api::CoreInterface::ActivityTaskCompletion.new(
|
|
77
105
|
task_token: task_token,
|
|
78
106
|
result: result,
|
|
79
107
|
)
|
|
80
|
-
encoded_proto =
|
|
108
|
+
encoded_proto = Temporalio::Bridge::Api::CoreInterface::ActivityTaskCompletion.encode(proto)
|
|
81
109
|
|
|
82
110
|
with_queue do |done|
|
|
83
111
|
core_worker.complete_activity_task(encoded_proto, &done)
|
|
84
112
|
end
|
|
85
113
|
end
|
|
114
|
+
|
|
115
|
+
def complete_workflow_activation(proto)
|
|
116
|
+
encoded_proto = Temporalio::Bridge::Api::WorkflowCompletion::WorkflowActivationCompletion.encode(proto)
|
|
117
|
+
|
|
118
|
+
with_queue do |done|
|
|
119
|
+
core_worker.complete_workflow_activation(encoded_proto, &done)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
86
122
|
end
|
|
87
123
|
end
|
|
88
124
|
end
|
data/lib/temporalio/worker.rb
CHANGED
|
@@ -4,10 +4,11 @@ require 'temporalio/data_converter'
|
|
|
4
4
|
require 'temporalio/runtime'
|
|
5
5
|
require 'temporalio/worker/activity_worker'
|
|
6
6
|
require 'temporalio/worker/runner'
|
|
7
|
+
require 'temporalio/worker/sync_worker'
|
|
7
8
|
require 'temporalio/worker/thread_pool_executor'
|
|
8
9
|
|
|
9
10
|
module Temporalio
|
|
10
|
-
# Worker to process
|
|
11
|
+
# Worker to process activities.
|
|
11
12
|
#
|
|
12
13
|
# Once created, workers can be run and shutdown explicitly via {#run} and {#shutdown}.
|
|
13
14
|
class Worker
|
|
@@ -40,7 +41,7 @@ module Temporalio
|
|
|
40
41
|
Runner.new(*workers).run(&block)
|
|
41
42
|
end
|
|
42
43
|
|
|
43
|
-
# Create a worker to process
|
|
44
|
+
# Create a worker to process activities.
|
|
44
45
|
#
|
|
45
46
|
# @param connection [Temporalio::Connection] A connection to be used for this worker.
|
|
46
47
|
# @param namespace [String] A namespace.
|
|
@@ -50,12 +51,14 @@ module Temporalio
|
|
|
50
51
|
# to/from payloads.
|
|
51
52
|
# @param activity_executor [ThreadPoolExecutor] Concurrent executor for all activities. Defaults
|
|
52
53
|
# to a {ThreadPoolExecutor} with `:max_concurrent_activities` available threads.
|
|
54
|
+
# @param interceptors [Array<Temporalio::Interceptor::ActivityInbound, Temporalio::Interceptor::ActivityOutbound>]
|
|
55
|
+
# Collection of interceptors for this worker.
|
|
53
56
|
# @param max_concurrent_activities [Integer] Number of concurrently running activities.
|
|
54
57
|
# @param graceful_shutdown_timeout [Integer] Amount of time (in seconds) activities are given
|
|
55
58
|
# after a shutdown to complete before they are cancelled. A default value of `nil` means that
|
|
56
59
|
# activities are never cancelled when handling a shutdown.
|
|
57
60
|
#
|
|
58
|
-
# @raise [ArgumentError] When no activities
|
|
61
|
+
# @raise [ArgumentError] When no activities have been provided.
|
|
59
62
|
def initialize(
|
|
60
63
|
connection,
|
|
61
64
|
namespace,
|
|
@@ -63,10 +66,10 @@ module Temporalio
|
|
|
63
66
|
activities: [],
|
|
64
67
|
data_converter: Temporalio::DataConverter.new,
|
|
65
68
|
activity_executor: nil,
|
|
69
|
+
interceptors: [],
|
|
66
70
|
max_concurrent_activities: 100,
|
|
67
71
|
graceful_shutdown_timeout: nil
|
|
68
72
|
)
|
|
69
|
-
# TODO: Add worker interceptors
|
|
70
73
|
@started = false
|
|
71
74
|
@shutdown = false
|
|
72
75
|
@mutex = Mutex.new
|
|
@@ -77,22 +80,26 @@ module Temporalio
|
|
|
77
80
|
connection.core_connection,
|
|
78
81
|
namespace,
|
|
79
82
|
task_queue,
|
|
83
|
+
0, # maxCachedWorkflows disabled temporarily
|
|
84
|
+
# FIXME: expose enable_non_local_activities
|
|
85
|
+
activities.empty?,
|
|
80
86
|
)
|
|
87
|
+
sync_worker = Worker::SyncWorker.new(@core_worker)
|
|
81
88
|
@activity_worker =
|
|
82
89
|
unless activities.empty?
|
|
83
90
|
Worker::ActivityWorker.new(
|
|
84
91
|
task_queue,
|
|
85
|
-
|
|
92
|
+
sync_worker,
|
|
86
93
|
activities,
|
|
87
94
|
data_converter,
|
|
95
|
+
interceptors,
|
|
88
96
|
@activity_executor,
|
|
89
97
|
graceful_shutdown_timeout,
|
|
90
98
|
)
|
|
91
99
|
end
|
|
92
|
-
@workflow_worker = nil
|
|
93
100
|
|
|
94
|
-
|
|
95
|
-
raise ArgumentError, 'At least one activity
|
|
101
|
+
unless @activity_worker
|
|
102
|
+
raise ArgumentError, 'At least one activity must be specified'
|
|
96
103
|
end
|
|
97
104
|
end
|
|
98
105
|
|
|
@@ -105,9 +112,9 @@ module Temporalio
|
|
|
105
112
|
# run it again.
|
|
106
113
|
#
|
|
107
114
|
# @yield Optionally you can provide a block by the end of which the worker will shut itself
|
|
108
|
-
# down. You can use this to stop a worker after some time has passed
|
|
109
|
-
#
|
|
110
|
-
#
|
|
115
|
+
# down. You can use this to stop a worker after some time has passed or any other arbitrary
|
|
116
|
+
# implementation has completed. Any errors raised from this block will be re-raised by this
|
|
117
|
+
# method.
|
|
111
118
|
def run(&block)
|
|
112
119
|
Runner.new(self).run(&block)
|
|
113
120
|
end
|
|
@@ -141,9 +148,6 @@ module Temporalio
|
|
|
141
148
|
shutdown(e) # initiate shutdown because of a fatal error
|
|
142
149
|
end
|
|
143
150
|
end
|
|
144
|
-
|
|
145
|
-
# TODO: Pending implementation
|
|
146
|
-
task.async { |task| workflow_worker.run(task) } if workflow_worker
|
|
147
151
|
end
|
|
148
152
|
end
|
|
149
153
|
|
|
@@ -158,17 +162,19 @@ module Temporalio
|
|
|
158
162
|
mutex.synchronize do
|
|
159
163
|
return unless running?
|
|
160
164
|
|
|
161
|
-
#
|
|
162
|
-
|
|
163
|
-
# Then let the runner know we're shutting down, so it can stop other workers
|
|
165
|
+
# Let the runner know we're shutting down, so it can stop other workers.
|
|
166
|
+
# This will cause a reentrant call to this method, but the mutex above will block that call.
|
|
164
167
|
runner&.shutdown(exception)
|
|
168
|
+
|
|
169
|
+
# Initiate Core shutdown, which will start dropping poll requests
|
|
170
|
+
core_worker.initiate_shutdown
|
|
171
|
+
# Start the graceful activity shutdown timer, which will cancel activities after the timeout
|
|
172
|
+
activity_worker&.setup_graceful_shutdown_timer(runtime.reactor)
|
|
165
173
|
# Wait for workers to drain any outstanding tasks
|
|
166
174
|
activity_worker&.drain
|
|
167
|
-
workflow_worker&.drain
|
|
168
|
-
# Stop the executor (at this point there should already be nothing in it)
|
|
169
175
|
activity_executor.shutdown
|
|
170
176
|
# Finalize the shutdown by stopping the Core
|
|
171
|
-
core_worker.
|
|
177
|
+
core_worker.finalize_shutdown
|
|
172
178
|
|
|
173
179
|
@shutdown = true
|
|
174
180
|
end
|
|
@@ -193,6 +199,6 @@ module Temporalio
|
|
|
193
199
|
private
|
|
194
200
|
|
|
195
201
|
attr_reader :mutex, :runtime, :activity_executor, :core_worker, :activity_worker,
|
|
196
|
-
:
|
|
202
|
+
:runner
|
|
197
203
|
end
|
|
198
204
|
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'temporalio/workflow/future'
|
|
2
|
+
|
|
3
|
+
module Temporalio
|
|
4
|
+
class Workflow
|
|
5
|
+
module Async
|
|
6
|
+
def self.run(&block)
|
|
7
|
+
Future.new do |future, resolve, reject|
|
|
8
|
+
Fiber.new do
|
|
9
|
+
Future.current = future
|
|
10
|
+
result = block.call
|
|
11
|
+
resolve.call(result)
|
|
12
|
+
rescue StandardError => e
|
|
13
|
+
reject.call(e)
|
|
14
|
+
end.resume
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.all(*futures)
|
|
19
|
+
Future.new do |future, resolve, _reject|
|
|
20
|
+
future.on_cancel { futures.each(&:cancel) }
|
|
21
|
+
|
|
22
|
+
futures.each do |f|
|
|
23
|
+
f.then do
|
|
24
|
+
# Resolve the aggregate once all futures have been fulfilled (resolved or rejected)
|
|
25
|
+
resolve.call(nil) if futures.none?(&:pending?)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.any(*futures)
|
|
32
|
+
# This future is never rejected
|
|
33
|
+
Future.new do |future, resolve, _reject|
|
|
34
|
+
future.on_cancel { futures.each(&:cancel) }
|
|
35
|
+
|
|
36
|
+
futures.each do |f|
|
|
37
|
+
# Resolve the aggregate once the first future fulfills (resolved or rejected)
|
|
38
|
+
# NOTE: The the first completed future will be the resolved value and all subsequent
|
|
39
|
+
# calls to `resolve` will have no effect.
|
|
40
|
+
f.then { resolve.call(f) }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
module Temporalio
|
|
2
|
+
class Workflow
|
|
3
|
+
class Future
|
|
4
|
+
THREAD_KEY = :temporalio_workflow_future
|
|
5
|
+
|
|
6
|
+
class Rejected < StandardError; end
|
|
7
|
+
|
|
8
|
+
def self.current
|
|
9
|
+
Thread.current[THREAD_KEY]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.current=(future)
|
|
13
|
+
Thread.current[THREAD_KEY] = future
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Revist the reason for combining futures and cancellation scopes, maybe they are separate?
|
|
17
|
+
def initialize(&block)
|
|
18
|
+
@resolved = false
|
|
19
|
+
@value = nil
|
|
20
|
+
@rejected = false
|
|
21
|
+
@error = Rejected.new('Future rejected')
|
|
22
|
+
@cancel_requested = false
|
|
23
|
+
@blocked_fibers = []
|
|
24
|
+
@callbacks = []
|
|
25
|
+
@cancel_callbacks = []
|
|
26
|
+
|
|
27
|
+
# Chain cancellation into parent future if one exists
|
|
28
|
+
Future.current&.on_cancel { cancel }
|
|
29
|
+
|
|
30
|
+
# NOTE: resolve and reject methods are accessible via procs to avoid exposing
|
|
31
|
+
# them via the public interface.
|
|
32
|
+
block.call(
|
|
33
|
+
self,
|
|
34
|
+
->(value) { resolve(value) },
|
|
35
|
+
->(error) { reject(error) },
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def then(&block)
|
|
40
|
+
Future.new do |future, resolve, reject|
|
|
41
|
+
# @type var wrapped_block: ^() -> void
|
|
42
|
+
wrapped_block = -> do # rubocop:disable Style/Lambda
|
|
43
|
+
Fiber.new do
|
|
44
|
+
Future.current = future
|
|
45
|
+
# The block is provided the Future on which #then was called
|
|
46
|
+
result = block.call(self)
|
|
47
|
+
resolve.call(result)
|
|
48
|
+
rescue StandardError => e
|
|
49
|
+
reject.call(e)
|
|
50
|
+
end.resume
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
if pending?
|
|
54
|
+
callbacks << wrapped_block
|
|
55
|
+
else
|
|
56
|
+
wrapped_block.call
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def on_cancel(&block)
|
|
62
|
+
if pending? && !cancel_requested?
|
|
63
|
+
cancel_callbacks << block
|
|
64
|
+
else
|
|
65
|
+
block.call
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def pending?
|
|
70
|
+
!resolved? && !rejected?
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def resolved?
|
|
74
|
+
@resolved
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def rejected?
|
|
78
|
+
@rejected
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def await
|
|
82
|
+
if pending?
|
|
83
|
+
blocked_fibers << Fiber.current
|
|
84
|
+
# yield into the parent fiber
|
|
85
|
+
Fiber.yield while pending?
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
raise error if rejected?
|
|
89
|
+
|
|
90
|
+
value
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def cancel
|
|
94
|
+
return unless pending?
|
|
95
|
+
return if cancel_requested?
|
|
96
|
+
|
|
97
|
+
@cancel_requested = true
|
|
98
|
+
cancel_callbacks.each(&:call)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
attr_reader :value, :error, :blocked_fibers, :callbacks, :cancel_callbacks
|
|
104
|
+
|
|
105
|
+
def cancel_requested?
|
|
106
|
+
@cancel_requested
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# TODO: Run callbacks in a Fiber to allow blocking calls
|
|
110
|
+
def run_callbacks
|
|
111
|
+
callbacks.each(&:call)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Unblock every fiber that this future is awaited on
|
|
115
|
+
def resume_fibers
|
|
116
|
+
blocked_fibers.each(&:resume)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def resolve(value)
|
|
120
|
+
return unless pending?
|
|
121
|
+
|
|
122
|
+
@value = value
|
|
123
|
+
@resolved = true
|
|
124
|
+
run_callbacks
|
|
125
|
+
resume_fibers
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def reject(error)
|
|
129
|
+
return unless pending?
|
|
130
|
+
|
|
131
|
+
@error = error
|
|
132
|
+
@rejected = true
|
|
133
|
+
run_callbacks
|
|
134
|
+
resume_fibers
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module Temporalio
|
|
2
|
+
class Workflow
|
|
3
|
+
# Class containing information about a workflow's parent.
|
|
4
|
+
class ParentInfo < Struct.new(
|
|
5
|
+
:namespace,
|
|
6
|
+
:run_id,
|
|
7
|
+
:workflow_id,
|
|
8
|
+
keyword_init: true,
|
|
9
|
+
)
|
|
10
|
+
# @!attribute [r] namespace
|
|
11
|
+
# @return [String] Namespace of the parent workflow.
|
|
12
|
+
# @!attribute [r] run_id
|
|
13
|
+
# @return [String] Run ID of the parent workflow.
|
|
14
|
+
# @!attribute [r] workflow_id
|
|
15
|
+
# @return [String] ID of the parent workflow.
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Class containing information about a workflow.
|
|
19
|
+
class Info < Struct.new(
|
|
20
|
+
:attempt,
|
|
21
|
+
:continued_run_id,
|
|
22
|
+
:cron_schedule,
|
|
23
|
+
:execution_timeout,
|
|
24
|
+
:headers,
|
|
25
|
+
:namespace,
|
|
26
|
+
:parent,
|
|
27
|
+
:raw_memo,
|
|
28
|
+
:retry_policy,
|
|
29
|
+
:run_id,
|
|
30
|
+
:run_timeout,
|
|
31
|
+
:search_attributes,
|
|
32
|
+
:start_time,
|
|
33
|
+
:task_queue,
|
|
34
|
+
:task_timeout,
|
|
35
|
+
:workflow_id,
|
|
36
|
+
:workflow_type,
|
|
37
|
+
keyword_init: true,
|
|
38
|
+
)
|
|
39
|
+
# @!attribute [r] attempt
|
|
40
|
+
# @return [Integer] Attempt of executing the workflow.
|
|
41
|
+
# @!attribute [r] continued_run_id
|
|
42
|
+
# @return [String] Run id of the previous workflow which continued-as-new or retired or cron
|
|
43
|
+
# executed into this workflow, if any.
|
|
44
|
+
# @!attribute [r] cron_schedule
|
|
45
|
+
# @return [String] Cron schedule of the workflow.
|
|
46
|
+
# @!attribute [r] execution_timeout
|
|
47
|
+
# @return [Float] Execution timeout of the workflow (in seconds).
|
|
48
|
+
# @!attribute [r] headers
|
|
49
|
+
# @return [Hash<String, any>] Headers for the workflow.
|
|
50
|
+
# @!attribute [r] namespace
|
|
51
|
+
# @return [String] Namespace of the workflow.
|
|
52
|
+
# @!attribute [r] parent
|
|
53
|
+
# @return [Temporalio::Workflow::ParentInfo] Info of the parent workflow.
|
|
54
|
+
# @!attribute [r] raw_memo
|
|
55
|
+
# @return [Hash<String, any>] Memo for the workflow.
|
|
56
|
+
# @!attribute [r] retry_policy
|
|
57
|
+
# @return [Temporalio::RetryPolicy] RetryPolicy of the workflow.
|
|
58
|
+
# @!attribute [r] run_id
|
|
59
|
+
# @return [String] Run ID of the workflow.
|
|
60
|
+
# @!attribute [r] run_timeout
|
|
61
|
+
# @return [Float] Run timeout of the workflow (in seconds).
|
|
62
|
+
# @!attribute [r] search_attributes
|
|
63
|
+
# @return [Hash<String, String>] Search attributes of the workflow.
|
|
64
|
+
# @!attribute [r] start_time
|
|
65
|
+
# @return [Time] Start time of the workflow.
|
|
66
|
+
# @!attribute [r] task_queue
|
|
67
|
+
# @return [String] Task queue of the workflow.
|
|
68
|
+
# @!attribute [r] task_timeout
|
|
69
|
+
# @return [Float] Task timeout of the workflow (in seconds).
|
|
70
|
+
# @!attribute [r] workflow_id
|
|
71
|
+
# @return [String] ID of the workflow.
|
|
72
|
+
# @!attribute [r] workflow_type
|
|
73
|
+
# @return [String] Type of the workflow.
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
data/temporalio.gemspec
CHANGED
|
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
|
8
8
|
spec.homepage = 'https://github.com/temporalio/sdk-ruby'
|
|
9
9
|
spec.licenses = ['MIT']
|
|
10
10
|
|
|
11
|
-
spec.authors = ['
|
|
12
|
-
spec.email = ['
|
|
11
|
+
spec.authors = ['Temporal Technologies Inc.']
|
|
12
|
+
spec.email = ['sdk@temporal.io']
|
|
13
13
|
|
|
14
14
|
spec.require_paths = ['lib']
|
|
15
15
|
spec.extensions = ['ext/Rakefile']
|
|
@@ -35,11 +35,12 @@ Gem::Specification.new do |spec|
|
|
|
35
35
|
spec.add_development_dependency 'protobuf' # Ruby implementation of protobufs (for rbs_protobuf)
|
|
36
36
|
spec.add_development_dependency 'pry' # Debugger
|
|
37
37
|
spec.add_development_dependency 'rake' # rake tasks
|
|
38
|
+
spec.add_development_dependency 'rbs', '>= 2.8.0', '< 3.0.0' # RBS - steep 1.3.0 crashes with RBS 3.0.0
|
|
38
39
|
spec.add_development_dependency 'rbs_protobuf' # RBS generator for protobufs
|
|
39
40
|
spec.add_development_dependency 'rspec' # specs
|
|
40
41
|
spec.add_development_dependency 'rubocop' # linter
|
|
41
42
|
spec.add_development_dependency 'rubocop-rspec' # spec linter
|
|
42
|
-
spec.add_development_dependency 'steep' # type checker
|
|
43
|
+
spec.add_development_dependency 'steep', '~> 1.3.0' # type checker
|
|
43
44
|
spec.add_development_dependency 'typeprof' # type generator
|
|
44
45
|
spec.add_development_dependency 'yard' # docs
|
|
45
46
|
end
|