Skip to content

Commit a9ca51d

Browse files
committed
Work on workflows
1 parent 0d0f841 commit a9ca51d

File tree

136 files changed

+13311
-758
lines changed

Some content is hidden

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

136 files changed

+13311
-758
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
jobs:
1010
build-lint-test:
1111
strategy:
12-
fail-fast: true
12+
fail-fast: false
1313
matrix:
1414
# TODO(cretz): Enable Linux ARM. It's not natively supported with setup-ruby (see
1515
# https://github.com/ruby/setup-ruby#supported-platforms and https://github.com/ruby/setup-ruby/issues/577).

README.md

Lines changed: 552 additions & 39 deletions
Large diffs are not rendered by default.

temporalio/.rubocop.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Layout/LeadingCommentSpace:
2929
Lint/MissingSuper:
3030
AllowedParentClasses:
3131
- Temporalio::Activity::Definition
32+
- Temporalio::Workflow::Definition
3233

3334
# The default is too small and triggers simply setting lots of values on a proto
3435
Metrics/AbcSize:
@@ -56,7 +57,7 @@ Metrics/ModuleLength:
5657

5758
# The default is too small
5859
Metrics/PerceivedComplexity:
59-
Max: 25
60+
Max: 40
6061

6162
# We want classes to be documented
6263
Style/Documentation:

temporalio/.yardopts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
--readme README.md
2+
--protected

temporalio/Rakefile

Lines changed: 9 additions & 294 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# frozen_string_literal: true
22

3-
# rubocop:disable Metrics/BlockLength, Lint/MissingCopEnableDirective, Style/DocumentationMethod
3+
# rubocop:disable Lint/MissingCopEnableDirective, Style/DocumentationMethod
44

55
require 'bundler/gem_tasks'
66
require 'rb_sys/cargo/metadata'
@@ -55,310 +55,25 @@ module CustomizeYardWarnings # rubocop:disable Style/Documentation
5555
super
5656
rescue YARD::Parser::UndocumentableError
5757
# We ignore if it's an API warning
58-
raise unless statement.last.file.start_with?('lib/temporalio/api/') ||
59-
statement.last.file.start_with?('lib/temporalio/internal/bridge/api/')
58+
last_file = statement.last.file
59+
raise unless (last_file.start_with?('lib/temporalio/api/') && last_file.count('/') > 3) ||
60+
last_file.start_with?('lib/temporalio/internal/bridge/api/')
6061
end
6162
end
6263

6364
YARD::Handlers::Ruby::ConstantHandler.prepend(CustomizeYardWarnings)
6465

6566
YARD::Rake::YardocTask.new { |t| t.options = ['--fail-on-warning'] }
6667

67-
require 'fileutils'
68-
require 'google/protobuf'
68+
Rake::Task[:yard].enhance([:copy_parent_files]) do
69+
rm ['LICENSE', 'README.md']
70+
end
6971

7072
namespace :proto do
7173
desc 'Generate API and Core protobufs'
7274
task :generate do
73-
# Remove all existing
74-
FileUtils.rm_rf('lib/temporalio/api')
75-
76-
def generate_protos(api_protos)
77-
# Generate API to temp dir and move
78-
FileUtils.rm_rf('tmp-proto')
79-
FileUtils.mkdir_p('tmp-proto')
80-
sh 'bundle exec grpc_tools_ruby_protoc ' \
81-
'--proto_path=ext/sdk-core/sdk-core-protos/protos/api_upstream ' \
82-
'--proto_path=ext/sdk-core/sdk-core-protos/protos/api_cloud_upstream ' \
83-
'--proto_path=ext/additional_protos ' \
84-
'--ruby_out=tmp-proto ' \
85-
"#{api_protos.join(' ')}"
86-
87-
# Walk all generated Ruby files and cleanup content and filename
88-
Dir.glob('tmp-proto/temporal/api/**/*.rb') do |path|
89-
# Fix up the import
90-
content = File.read(path)
91-
content.gsub!(%r{^require 'temporal/(.*)_pb'$}, "require 'temporalio/\\1'")
92-
File.write(path, content)
93-
94-
# Remove _pb from the filename
95-
FileUtils.mv(path, path.sub('_pb', ''))
96-
end
97-
98-
# Move from temp dir and remove temp dir
99-
FileUtils.cp_r('tmp-proto/temporal/api', 'lib/temporalio')
100-
FileUtils.rm_rf('tmp-proto')
101-
end
102-
103-
# Generate from API with Google ones removed
104-
generate_protos(Dir.glob('ext/sdk-core/sdk-core-protos/protos/api_upstream/**/*.proto').reject do |proto|
105-
proto.include?('google')
106-
end)
107-
108-
# Generate from Cloud API
109-
generate_protos(Dir.glob('ext/sdk-core/sdk-core-protos/protos/api_cloud_upstream/**/*.proto'))
110-
111-
# Generate additional protos
112-
generate_protos(Dir.glob('ext/additional_protos/**/*.proto'))
113-
114-
# Write files that will help with imports. We are requiring the
115-
# request_response and not the service because the service depends on Google
116-
# API annotations we don't want to have to depend on.
117-
File.write(
118-
'lib/temporalio/api/cloud/cloudservice.rb',
119-
<<~TEXT
120-
# frozen_string_literal: true
121-
122-
require 'temporalio/api/cloud/cloudservice/v1/request_response'
123-
TEXT
124-
)
125-
File.write(
126-
'lib/temporalio/api/workflowservice.rb',
127-
<<~TEXT
128-
# frozen_string_literal: true
129-
130-
require 'temporalio/api/workflowservice/v1/request_response'
131-
TEXT
132-
)
133-
File.write(
134-
'lib/temporalio/api/operatorservice.rb',
135-
<<~TEXT
136-
# frozen_string_literal: true
137-
138-
require 'temporalio/api/operatorservice/v1/request_response'
139-
TEXT
140-
)
141-
File.write(
142-
'lib/temporalio/api.rb',
143-
<<~TEXT
144-
# frozen_string_literal: true
145-
146-
require 'temporalio/api/cloud/cloudservice'
147-
require 'temporalio/api/common/v1/grpc_status'
148-
require 'temporalio/api/errordetails/v1/message'
149-
require 'temporalio/api/operatorservice'
150-
require 'temporalio/api/workflowservice'
151-
152-
module Temporalio
153-
# Raw protocol buffer models.
154-
module Api
155-
end
156-
end
157-
TEXT
158-
)
159-
160-
# Write the service classes that have the RPC calls
161-
def write_service_file(qualified_service_name:, file_name:, class_name:, service_enum:)
162-
# Do service lookup
163-
desc = Google::Protobuf::DescriptorPool.generated_pool.lookup(qualified_service_name)
164-
raise 'Failed finding service descriptor' unless desc
165-
166-
# Open file to generate Ruby code
167-
File.open("lib/temporalio/client/connection/#{file_name}.rb", 'w') do |file|
168-
file.puts <<~TEXT
169-
# frozen_string_literal: true
170-
171-
# Generated code. DO NOT EDIT!
172-
173-
require 'temporalio/api'
174-
require 'temporalio/client/connection/service'
175-
require 'temporalio/internal/bridge/client'
176-
177-
module Temporalio
178-
class Client
179-
class Connection
180-
# #{class_name} API.
181-
class #{class_name} < Service
182-
# @!visibility private
183-
def initialize(connection)
184-
super(connection, Internal::Bridge::Client::#{service_enum})
185-
end
186-
TEXT
187-
188-
desc.each do |method|
189-
# Camel case to snake case
190-
rpc = method.name.gsub(/([A-Z])/, '_\1').downcase.delete_prefix('_')
191-
file.puts <<-TEXT
192-
193-
# Calls #{class_name}.#{method.name} API call.
194-
#
195-
# @param request [#{method.input_type.msgclass}] API request.
196-
# @param rpc_options [RPCOptions, nil] Advanced RPC options.
197-
# @return [#{method.output_type.msgclass}] API response.
198-
def #{rpc}(request, rpc_options: nil)
199-
invoke_rpc(
200-
rpc: '#{rpc}',
201-
request_class: #{method.input_type.msgclass},
202-
response_class: #{method.output_type.msgclass},
203-
request:,
204-
rpc_options:
205-
)
206-
end
207-
TEXT
208-
end
209-
210-
file.puts <<~TEXT
211-
end
212-
end
213-
end
214-
end
215-
TEXT
216-
end
217-
218-
# Open file to generate RBS code
219-
# TODO(cretz): Improve this when RBS proto is supported
220-
File.open("sig/temporalio/client/connection/#{file_name}.rbs", 'w') do |file|
221-
file.puts <<~TEXT
222-
# Generated code. DO NOT EDIT!
223-
224-
module Temporalio
225-
class Client
226-
class Connection
227-
class #{class_name} < Service
228-
def initialize: (Connection) -> void
229-
TEXT
230-
231-
desc.each do |method|
232-
# Camel case to snake case
233-
rpc = method.name.gsub(/([A-Z])/, '_\1').downcase.delete_prefix('_')
234-
file.puts <<-TEXT
235-
def #{rpc}: (
236-
untyped request,
237-
?rpc_options: RPCOptions?
238-
) -> untyped
239-
TEXT
240-
end
241-
242-
file.puts <<~TEXT
243-
end
244-
end
245-
end
246-
end
247-
TEXT
248-
end
249-
end
250-
251-
require './lib/temporalio/api/workflowservice/v1/service'
252-
write_service_file(
253-
qualified_service_name: 'temporal.api.workflowservice.v1.WorkflowService',
254-
file_name: 'workflow_service',
255-
class_name: 'WorkflowService',
256-
service_enum: 'SERVICE_WORKFLOW'
257-
)
258-
require './lib/temporalio/api/operatorservice/v1/service'
259-
write_service_file(
260-
qualified_service_name: 'temporal.api.operatorservice.v1.OperatorService',
261-
file_name: 'operator_service',
262-
class_name: 'OperatorService',
263-
service_enum: 'SERVICE_OPERATOR'
264-
)
265-
require './lib/temporalio/api/cloud/cloudservice/v1/service'
266-
write_service_file(
267-
qualified_service_name: 'temporal.api.cloud.cloudservice.v1.CloudService',
268-
file_name: 'cloud_service',
269-
class_name: 'CloudService',
270-
service_enum: 'SERVICE_CLOUD'
271-
)
272-
273-
# Generate Rust code
274-
def generate_rust_match_arm(file:, qualified_service_name:, service_enum:, trait:)
275-
# Do service lookup
276-
desc = Google::Protobuf::DescriptorPool.generated_pool.lookup(qualified_service_name)
277-
file.puts <<~TEXT
278-
#{service_enum} => match call.rpc.as_str() {
279-
TEXT
280-
281-
desc.to_a.sort_by(&:name).each do |method|
282-
# Camel case to snake case
283-
rpc = method.name.gsub(/([A-Z])/, '_\1').downcase.delete_prefix('_')
284-
file.puts <<~TEXT
285-
"#{rpc}" => rpc_call!(self, callback, call, #{trait}, #{rpc}),
286-
TEXT
287-
end
288-
file.puts <<~TEXT
289-
_ => Err(error!("Unknown RPC call {}", call.rpc)),
290-
},
291-
TEXT
292-
end
293-
File.open('ext/src/client_rpc_generated.rs', 'w') do |file|
294-
file.puts <<~TEXT
295-
// Generated code. DO NOT EDIT!
296-
297-
use magnus::{Error, Ruby};
298-
use temporal_client::{CloudService, OperatorService, WorkflowService};
299-
300-
use super::{error, rpc_call};
301-
use crate::{
302-
client::{Client, RpcCall, SERVICE_CLOUD, SERVICE_OPERATOR, SERVICE_WORKFLOW},
303-
util::AsyncCallback,
304-
};
305-
306-
impl Client {
307-
pub fn invoke_rpc(&self, service: u8, callback: AsyncCallback, call: RpcCall) -> Result<(), Error> {
308-
match service {
309-
TEXT
310-
generate_rust_match_arm(
311-
file:,
312-
qualified_service_name: 'temporal.api.workflowservice.v1.WorkflowService',
313-
service_enum: 'SERVICE_WORKFLOW',
314-
trait: 'WorkflowService'
315-
)
316-
generate_rust_match_arm(
317-
file:,
318-
qualified_service_name: 'temporal.api.operatorservice.v1.OperatorService',
319-
service_enum: 'SERVICE_OPERATOR',
320-
trait: 'OperatorService'
321-
)
322-
generate_rust_match_arm(
323-
file:,
324-
qualified_service_name: 'temporal.api.cloud.cloudservice.v1.CloudService',
325-
service_enum: 'SERVICE_CLOUD',
326-
trait: 'CloudService'
327-
)
328-
file.puts <<~TEXT
329-
_ => Err(error!("Unknown service")),
330-
}
331-
}
332-
}
333-
TEXT
334-
end
335-
sh 'cargo', 'fmt', '--', 'ext/src/client_rpc_generated.rs'
336-
337-
# Generate core protos
338-
FileUtils.rm_rf('lib/temporalio/internal/bridge/api')
339-
# Generate API to temp dir
340-
FileUtils.rm_rf('tmp-proto')
341-
FileUtils.mkdir_p('tmp-proto')
342-
sh 'bundle exec grpc_tools_ruby_protoc ' \
343-
'--proto_path=ext/sdk-core/sdk-core-protos/protos/api_upstream ' \
344-
'--proto_path=ext/sdk-core/sdk-core-protos/protos/local ' \
345-
'--ruby_out=tmp-proto ' \
346-
"#{Dir.glob('ext/sdk-core/sdk-core-protos/protos/local/**/*.proto').join(' ')}"
347-
# Walk all generated Ruby files and cleanup content and filename
348-
Dir.glob('tmp-proto/temporal/sdk/**/*.rb') do |path|
349-
# Fix up the imports
350-
content = File.read(path)
351-
content.gsub!(%r{^require 'temporal/(.*)_pb'$}, "require 'temporalio/\\1'")
352-
content.gsub!(%r{^require 'temporalio/sdk/core/(.*)'$}, "require 'temporalio/internal/bridge/api/\\1'")
353-
File.write(path, content)
354-
355-
# Remove _pb from the filename
356-
FileUtils.mv(path, path.sub('_pb', ''))
357-
end
358-
# Move from temp dir and remove temp dir
359-
FileUtils.mkdir_p('lib/temporalio/internal/bridge/api')
360-
FileUtils.cp_r(Dir.glob('tmp-proto/temporal/sdk/core/*'), 'lib/temporalio/internal/bridge/api')
361-
FileUtils.rm_rf('tmp-proto')
75+
require_relative 'extra/proto_gen'
76+
ProtoGen.new.run
36277
end
36378
end
36479

temporalio/ext/src/client_rpc_generated.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// Generated code. DO NOT EDIT!
22

33
use magnus::{Error, Ruby};
4-
use temporal_client::{CloudService, OperatorService, WorkflowService};
4+
use temporal_client::{CloudService, OperatorService, TestService, WorkflowService};
55

66
use super::{error, rpc_call};
77
use crate::{
8-
client::{Client, RpcCall, SERVICE_CLOUD, SERVICE_OPERATOR, SERVICE_WORKFLOW},
8+
client::{Client, RpcCall, SERVICE_CLOUD, SERVICE_OPERATOR, SERVICE_TEST, SERVICE_WORKFLOW},
99
util::AsyncCallback,
1010
};
1111

@@ -516,6 +516,27 @@ impl Client {
516516
}
517517
_ => Err(error!("Unknown RPC call {}", call.rpc)),
518518
},
519+
SERVICE_TEST => match call.rpc.as_str() {
520+
"get_current_time" => {
521+
rpc_call!(self, callback, call, TestService, get_current_time)
522+
}
523+
"lock_time_skipping" => {
524+
rpc_call!(self, callback, call, TestService, lock_time_skipping)
525+
}
526+
"sleep" => rpc_call!(self, callback, call, TestService, sleep),
527+
"sleep_until" => rpc_call!(self, callback, call, TestService, sleep_until),
528+
"unlock_time_skipping" => {
529+
rpc_call!(self, callback, call, TestService, unlock_time_skipping)
530+
}
531+
"unlock_time_skipping_with_sleep" => rpc_call!(
532+
self,
533+
callback,
534+
call,
535+
TestService,
536+
unlock_time_skipping_with_sleep
537+
),
538+
_ => Err(error!("Unknown RPC call {}", call.rpc)),
539+
},
519540
_ => Err(error!("Unknown service")),
520541
}
521542
}

0 commit comments

Comments
 (0)