Skip to content

Commit 83bea60

Browse files
authored
More client work (#159)
1 parent ff47b2e commit 83bea60

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+3536
-492
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ To build shared library for development use:
2626
Note, this is not `compile:dev` because debug-mode in Rust has
2727
[an issue](https://github.com/rust-lang/rust/issues/34283) that causes runtime stack size problems.
2828

29-
To build and test release:
29+
To lint, build, and test release:
3030

3131
bundle exec rake
3232

temporalio/.rubocop.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Layout/ClassStructure:
2626

2727
# The default is too small and triggers simply setting lots of values on a proto
2828
Metrics/AbcSize:
29-
Max: 75
29+
Max: 200
3030

3131
# The default is too small
3232
Metrics/BlockLength:
@@ -44,6 +44,10 @@ Metrics/CyclomaticComplexity:
4444
Metrics/MethodLength:
4545
Max: 100
4646

47+
# The default is too small
48+
Metrics/ModuleLength:
49+
Max: 1000
50+
4751
# The default is too small
4852
Metrics/PerceivedComplexity:
4953
Max: 25

temporalio/Rakefile

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,18 @@ Steep::RakeTask.new
3333

3434
require 'yard'
3535

36-
YARD::Rake::YardocTask.new
36+
module CustomizeYardWarnings # rubocop:disable Style/Documentation
37+
def process
38+
super
39+
rescue YARD::Parser::UndocumentableError
40+
# We ignore if it's an API warning
41+
raise unless statement.last.file.start_with?('lib/temporalio/api/')
42+
end
43+
end
44+
45+
YARD::Handlers::Ruby::ConstantHandler.prepend(CustomizeYardWarnings)
46+
47+
YARD::Rake::YardocTask.new { |t| t.options = ['--fail-on-warning'] }
3748

3849
require 'fileutils'
3950
require 'google/protobuf'
@@ -321,4 +332,4 @@ Rake::Task[:build].enhance([:copy_parent_files]) do
321332
rm ['LICENSE', 'README.md']
322333
end
323334

324-
task default: ['rubocop', 'compile', 'rbs:install_collection', 'steep', 'test']
335+
task default: ['rubocop', 'yard', 'compile', 'rbs:install_collection', 'steep', 'test']

temporalio/lib/temporalio/client.rb

Lines changed: 75 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@
22

33
require 'google/protobuf/well_known_types'
44
require 'temporalio/api'
5+
require 'temporalio/client/async_activity_handle'
56
require 'temporalio/client/connection'
7+
require 'temporalio/client/implementation'
68
require 'temporalio/client/interceptor'
9+
require 'temporalio/client/workflow_execution'
10+
require 'temporalio/client/workflow_execution_count'
711
require 'temporalio/client/workflow_handle'
12+
require 'temporalio/client/workflow_query_reject_condition'
813
require 'temporalio/common_enums'
914
require 'temporalio/converters'
1015
require 'temporalio/error'
11-
require 'temporalio/internal/proto_utils'
16+
require 'temporalio/retry_policy'
1217
require 'temporalio/runtime'
1318
require 'temporalio/search_attributes'
1419

@@ -45,10 +50,10 @@ class Client
4550
# TLS options are present, those TLS options will be used.
4651
# @param data_converter [Converters::DataConverter] Data converter to use for all data conversions to/from payloads.
4752
# @param interceptors [Array<Interceptor>] Set of interceptors that are chained together to allow intercepting of
48-
# client calls. The earlier interceptors wrap the later ones. Any interceptors that also implement
49-
# {Worker::Interceptor} will be used as worker interceptors too so they should not be given separately when
50-
# creating a worker.
51-
# @param default_workflow_query_reject_condition [Api::Enums::V1::QueryRejectCondition, nil] Default rejection
53+
# client calls. The earlier interceptors wrap the later ones. Any interceptors that also implement worker
54+
# interceptor will be used as worker interceptors too so they should not be given separately when creating a
55+
# worker.
56+
# @param default_workflow_query_reject_condition [WorkflowQueryRejectCondition, nil] Default rejection
5257
# condition for workflow queries if not set during query. See {WorkflowHandle.query} for details on the
5358
# rejection condition.
5459
# @param rpc_metadata [Hash<String, String>] Headers to use for all calls to the server. Keys here can be overriden
@@ -116,11 +121,10 @@ def self.connect(
116121
# @param interceptors [Array<Interceptor>] Set of interceptors that are chained together to allow intercepting of
117122
# client calls. The earlier interceptors wrap the later ones.
118123
#
119-
# Any interceptors that also implement {Worker::Interceptor} will be used as worker interceptors too so they
120-
# should not be given separately when creating a worker.
121-
# @param default_workflow_query_reject_condition [Api::Enums::V1::QueryRejectCondition, nil] Default rejection
122-
# condition for workflow queries if not set during query. See {WorkflowHandle.query} for details on the
123-
# rejection condition.
124+
# Any interceptors that also implement worker interceptor will be used as worker interceptors too so they should
125+
# not be given separately when creating a worker.
126+
# @param default_workflow_query_reject_condition [WorkflowQueryRejectCondition, nil] Default rejection condition for
127+
# workflow queries if not set during query. See {WorkflowHandle.query} for details on the rejection condition.
124128
#
125129
# @see connect
126130
def initialize(
@@ -218,7 +222,7 @@ def start_workflow(
218222
@impl.start_workflow(Interceptor::StartWorkflowInput.new(
219223
workflow:,
220224
args:,
221-
id:,
225+
workflow_id: id,
222226
task_queue:,
223227
execution_timeout:,
224228
run_timeout:,
@@ -264,7 +268,7 @@ def start_workflow(
264268
#
265269
# @return [Object] Successful result of the workflow.
266270
# @raise [Error::WorkflowAlreadyStartedError] Workflow already exists.
267-
# @raise [Error::WorkflowFailureError] Workflow failed with {Error::WorkflowFailureError.cause} as cause.
271+
# @raise [Error::WorkflowFailureError] Workflow failed with +cause+ as the cause.
268272
# @raise [Error::RPCError] RPC error from call.
269273
def execute_workflow(
270274
workflow,
@@ -320,103 +324,72 @@ def workflow_handle(
320324
run_id: nil,
321325
first_execution_run_id: nil
322326
)
323-
WorkflowHandle.new(self, workflow_id, run_id:, result_run_id: run_id, first_execution_run_id:)
327+
WorkflowHandle.new(client: self, id: workflow_id, run_id:, result_run_id: run_id, first_execution_run_id:)
324328
end
325329

326-
# @!visibility private
327-
def _impl
328-
@impl
330+
# List workflows.
331+
#
332+
# @param query [String, nil] A Temporal visibility list filter.
333+
# @param rpc_metadata [Hash<String, String>, nil] Headers to include on the RPC call.
334+
# @param rpc_timeout [Float, nil] Number of seconds before timeout.
335+
#
336+
# @return [Enumerator<WorkflowExecution>] Enumerable workflow executions.
337+
#
338+
# @raise [Error::RPCError] RPC error from call.
339+
#
340+
# @see https://docs.temporal.io/visibility
341+
def list_workflows(
342+
query = nil,
343+
rpc_metadata: nil,
344+
rpc_timeout: nil
345+
)
346+
@impl.list_workflows(Interceptor::ListWorkflowsInput.new(
347+
query:,
348+
rpc_metadata:,
349+
rpc_timeout:
350+
))
329351
end
330352

331-
# @!visibility private
332-
class Implementation < Interceptor::Outbound
333-
def initialize(client)
334-
super(nil)
335-
@client = client
336-
end
337-
338-
# @!visibility private
339-
def start_workflow(input)
340-
# TODO(cretz): Signal/update with start
341-
req = Api::WorkflowService::V1::StartWorkflowExecutionRequest.new(
342-
request_id: SecureRandom.uuid,
343-
namespace: @client.namespace,
344-
workflow_type: Api::Common::V1::WorkflowType.new(name: input.workflow.to_s),
345-
workflow_id: input.id,
346-
task_queue: Api::TaskQueue::V1::TaskQueue.new(name: input.task_queue.to_s),
347-
input: @client.data_converter.to_payloads(input.args),
348-
workflow_execution_timeout: Internal::ProtoUtils.seconds_to_duration(input.execution_timeout),
349-
workflow_run_timeout: Internal::ProtoUtils.seconds_to_duration(input.run_timeout),
350-
workflow_task_timeout: Internal::ProtoUtils.seconds_to_duration(input.task_timeout),
351-
identity: @client.connection.identity,
352-
workflow_id_reuse_policy: input.id_reuse_policy,
353-
workflow_id_conflict_policy: input.id_conflict_policy,
354-
retry_policy: input.retry_policy&.to_proto,
355-
cron_schedule: input.cron_schedule,
356-
memo: Internal::ProtoUtils.memo_to_proto(input.memo, @client.data_converter),
357-
search_attributes: input.search_attributes&.to_proto,
358-
workflow_start_delay: Internal::ProtoUtils.seconds_to_duration(input.start_delay),
359-
request_eager_execution: input.request_eager_start,
360-
header: input.headers
361-
)
362-
363-
# Send request
364-
begin
365-
resp = @client.workflow_service.start_workflow_execution(
366-
req,
367-
rpc_retry: true,
368-
rpc_metadata: input.rpc_metadata,
369-
rpc_timeout: input.rpc_timeout
370-
)
371-
rescue Error::RPCError => e
372-
# Unpack and raise already started if that's the error, otherwise default raise
373-
if e.code == Error::RPCError::Code::ALREADY_EXISTS && e.grpc_status.details.first
374-
details = e.grpc_status.details.first.unpack(Api::ErrorDetails::V1::WorkflowExecutionAlreadyStartedFailure)
375-
if details
376-
raise Error::WorkflowAlreadyStartedError.new(
377-
workflow_id: req.workflow_id,
378-
workflow_type: req.workflow_type.name,
379-
run_id: details.run_id
380-
)
381-
end
382-
end
383-
raise
384-
end
353+
# Count workflows.
354+
#
355+
# @param query [String, nil] A Temporal visibility list filter.
356+
# @param rpc_metadata [Hash<String, String>, nil] Headers to include on the RPC call.
357+
# @param rpc_timeout [Float, nil] Number of seconds before timeout.
358+
#
359+
# @return [WorkflowExecutionCount] Count of workflows.
360+
#
361+
# @raise [Error::RPCError] RPC error from call.
362+
#
363+
# @see https://docs.temporal.io/visibility
364+
def count_workflows(
365+
query = nil,
366+
rpc_metadata: nil,
367+
rpc_timeout: nil
368+
)
369+
@impl.count_workflows(Interceptor::CountWorkflowsInput.new(
370+
query:,
371+
rpc_metadata:,
372+
rpc_timeout:
373+
))
374+
end
385375

386-
# Return handle
387-
WorkflowHandle.new(
388-
@client,
389-
input.id,
390-
result_run_id: resp.run_id,
391-
first_execution_run_id: resp.run_id
392-
)
376+
# Get an async activity handle.
377+
#
378+
# @param task_token_or_id_reference [String, ActivityIDReference] Task token string or activity ID reference.
379+
# @return [AsyncActivityHandle]
380+
def async_activity_handle(task_token_or_id_reference)
381+
if task_token_or_id_reference.is_a?(ActivityIDReference)
382+
AsyncActivityHandle.new(client: self, task_token: nil, id_reference: task_token_or_id_reference)
383+
elsif task_token_or_id_reference.is_a?(String)
384+
AsyncActivityHandle.new(client: self, task_token: task_token_or_id_reference, id_reference: nil)
385+
else
386+
raise ArgumentError, 'Must be a string task token or an ActivityIDReference'
393387
end
388+
end
394389

395-
# @!visibility private
396-
def fetch_workflow_history_event_page(input)
397-
req = Api::WorkflowService::V1::GetWorkflowExecutionHistoryRequest.new(
398-
namespace: @client.namespace,
399-
execution: Api::Common::V1::WorkflowExecution.new(
400-
workflow_id: input.id,
401-
run_id: input.run_id || ''
402-
),
403-
maximum_page_size: input.page_size || 0,
404-
next_page_token: input.next_page_token,
405-
wait_new_event: input.wait_new_event,
406-
history_event_filter_type: input.event_filter_type,
407-
skip_archival: input.skip_archival
408-
)
409-
resp = @client.workflow_service.get_workflow_execution_history(
410-
req,
411-
rpc_retry: true,
412-
rpc_metadata: input.rpc_metadata,
413-
rpc_timeout: input.rpc_timeout
414-
)
415-
Interceptor::FetchWorkflowHistoryEventPage.new(
416-
events: resp.history&.events || [],
417-
next_page_token: resp.next_page_token.empty? ? nil : resp.next_page_token
418-
)
419-
end
390+
# @!visibility private
391+
def _impl
392+
@impl
420393
end
421394
end
422395
end
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# frozen_string_literal: true
2+
3+
require 'temporalio/api'
4+
require 'temporalio/client/interceptor'
5+
require 'temporalio/error'
6+
7+
module Temporalio
8+
class Client
9+
# Reference to an existing activity by its workflow ID, run ID, and activity ID.
10+
class ActivityIDReference
11+
# @return [String] ID for the workflow.
12+
attr_reader :workflow_id
13+
14+
# @return [String, nil] Run ID for the workflow.
15+
attr_reader :run_id
16+
17+
# @return [String] ID for the activity.
18+
attr_reader :activity_id
19+
20+
# Create an activity ID reference.
21+
#
22+
# @param workflow_id [String] ID for the workflow.
23+
# @param run_id [String, nil] Run ID for the workflow.
24+
# @param activity_id [String] ID for the workflow.
25+
def initialize(workflow_id:, run_id:, activity_id:)
26+
@workflow_id = workflow_id
27+
@run_id = run_id
28+
@activity_id = activity_id
29+
end
30+
end
31+
end
32+
end

0 commit comments

Comments
 (0)