Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scaffolding and bare-bones client #155

Merged
merged 4 commits into from
Aug 9, 2024
Merged

Conversation

cretz
Copy link
Member

@cretz cretz commented Jul 16, 2024

What was changed

  • Added scaffolding including:
    • Gem setup (including RBS, yard, minitest, etc)
    • magnus/rb-sys-based Rust extension
    • GH actions
    • Go-based test worker
  • Added basic Temporalio::Client with most basic features and a single basic test

Many things were not done that will be done shortly including:

  • Complete client
  • Tests
  • Complete testing environments
  • Failure converters and payload codecs

Ideally the review can focus more on the high-level approach and not get too bogged down in English of the API docs (which mostly came from Python and can be improved incrementally). Much of this is covered in the proposal.

Checklist

  1. Closes [Feature Request] Scaffolding and bare-bones client #154

"start_workflow_execution" => {
rpc_call!(self, block, call, start_workflow_execution)
}
_ => Err(error!("Unknown RPC call {}", call.rpc)),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obviously going to have a lot more here. We manually add these in .NET and Python because they don't get added that often, and we may do the same here, but we will have a test to confirm every one is present and works.

* [Protobuf Compiler](https://protobuf.dev/) (i.e. `protoc` on the `PATH`)
* This repository, cloned recursively
* Change to the `temporalio/` directory
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We chose to move this to a subdir because we expect other gems (e.g. temporalio-opentelemetry) and we don't want too many top-level files that move the README contents below the fold when arriving at the repo.

@cretz cretz requested a review from a team July 16, 2024 21:57
@cretz cretz marked this pull request as ready for review July 16, 2024 21:59
Copy link
Member Author

@cretz cretz Jul 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a lot of things in this file that I blindly brought over from https://github.com/temporalio/sdk-core/blob/master/Cargo.toml. This is likely only going to every be a 1-member workspace (it's just needed at the top level for tooling). Consider getting rid of everything in here except members and moving things to specific project toml if they need to be retained.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added docs to the top of this file explaining why it has to be this way right now

Copy link
Member

@Sushisource Sushisource left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good to me. I focused on the runtime / bridge part of things and didn't look in exacting detail at the client/dataconverter stuff which seems fairly straightforward and much like the others at this point anyway.

Comment on lines 160 to 162
// Ignore fail since we don't properly catch panics in
// without_gvl right now
let _ = self.handle.async_command_tx.send(AsyncCommand::Shutdown);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe error log here at least so if something weird is happening you might have an idea why

Comment on lines +14 to +16
# client. To create another client on the same connection, like for a different namespace, {dup_options} may be
# used to get the options as a struct which can then be altered and splatted as kwargs to the constructor (e.g.
# +Client.new(**my_options.to_h)+).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not urgent but feels like it'd be a lot more convenient to provide a client.new_client_with_changes(...) function that you can just pass the kwargs of what you want to override and then it does this bit for you.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a rare need I think, and I want to give people the ability to get their options back anyways. They may want to do more w/ them than just mutate+reinstantiate. What some Ruby libraries do is allow the configuration to occur in a block, e.g.:

my_new_client = my_client.new_with_changes do |options|
  # What if I want to do more than just simple override?
  options.namespace = 'my other namespace'
end

But I think this is a rare enough need (here and in other SDKs), that this is enough:

options = my_client.dup_options
options.namespace = 'my other namespace'
my_new_client = Client::new(**options.to_h)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's definitely not important. The former looks pretty nice I think but, I agree this is rare to need to do.

desc.each do |method|
# Camel case to snake case
rpc = method.name.gsub(/([A-Z])/, '_\1').downcase.delete_prefix('_')
define_method(rpc.to_sym) do |request, rpc_retry: false, rpc_metadata: {}, rpc_timeout_ms: 0|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A little bit easier than all the macros I had to write lol

rpc_timeout_ms:
)
response_bytes = Bridge.async_call do |queue|
async_invoke_rpc(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty neat

# @return [LoggingOptions, nil] Logging options, default is new {LoggingOptions} with no parameters.
# @!attribute metrics
# @return [MetricsOptions, nil] Metrics options.
TelemetryOptions = Struct.new(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works for me

Comment on lines +300 to +301
// TODO(cretz): Any reasonable way to prevent byte copy that is just going to get decoded into proto
// object?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There probably is, but it might also be more effort than it's worth. You'd have to pass around some explicit lifetime-having struct here or something. Hard for me to say without playing with the code myself but I could try it out if you like

Copy link
Member Author

@cretz cretz Jul 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think I found a way with rb_str_new_static (which magnus doesn't expose directly, but uses for static literals in r_string! IIUC). To do it safely, I'd have to probably unhook it from Rust (i.e. in a forgotten box) and put it back for dropping on RString GC. Can't even have a predictable time it could be dropped because I think Ruby GC has certain expectations here even after use.

But yeah it's a dangerous lifetime game to play save these cycles. I'll consider it premature optimization for now and we can come back later if needed.

@cretz cretz merged commit 5d17d1d into temporalio:main Aug 9, 2024
8 checks passed
@cretz cretz deleted the initial-client branch August 9, 2024 19:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature Request] Scaffolding and bare-bones client
2 participants