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

Initial workflow client #14

Merged
merged 13 commits into from
Jan 30, 2023
Merged

Initial workflow client #14

merged 13 commits into from
Jan 30, 2023

Conversation

cretz
Copy link
Member

@cretz cretz commented Jan 24, 2023

What was changed

  • Start workflow and get workflow result
  • Workflow attributes
  • Tests and scaffolding for the above
  • EDIT: added all the rest of the client features, this is now a full-fledged SDK client

Note, this does not yet include all tests or all features. I am trying to get this in front of people early. I may continue to work on parts for this PR while it remains unapproved.

EDIT: This thing is full featured and ready to go.

@cretz cretz requested a review from a team January 24, 2023 20:34
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 pretty good! Nothing blocking

),
Err(err) => match err.downcast::<tonic::Status>() {
Copy link
Member

Choose a reason for hiding this comment

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

I think the downcast could be fairly easily avoided by changing the various call methods/macros to return enum errors (use thiserror or w/e) rather than anyhow errors. They could even be tonic | other. Makes this match a bit cleaner and the code a bit more maintainable.

Copy link
Member Author

Choose a reason for hiding this comment

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

While it does make the match a bit cleaner, that my macros can return any error like inability to decode protos does make that code cleaner (though yes I could have a NotTonic(anyhow::Error)).

Copy link
Member

Choose a reason for hiding this comment

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

The macros should end up with the ability to work the same if you use the auto-From implementations generated by thiserror

src/Temporalio/Client/WorkflowHandle.cs Outdated Show resolved Hide resolved
public async Task<TResult> GetResultAsync<TResult>(
bool followRuns = true, RpcOptions? rpcOptions = null)
{
// Continually get pages
Copy link
Member

Choose a reason for hiding this comment

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

It's a little sad that we reimplement pagination in every SDK. This could all be encapsulated in Core if we want (the code is there already), but I suppose we lose out on some low level interception (which I doubt anyone cares much about).

WDYT?

Copy link
Member Author

Choose a reason for hiding this comment

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

Usually I would concur, however I am about to write the history event async iterator which needs to control paging anyways so there'd be no value here. I wrote the interceptor and single-page fetching the way I did here with the expectation of reuse.

src/Temporalio/Client/WorkflowHandle.cs Outdated Show resolved Hide resolved
Comment on lines +33 to +36
/// gRPC status code taken from
/// https://github.com/grpc/grpc-dotnet/blob/master/src/Grpc.Core.Api/StatusCode.cs.
/// </summary>
public enum StatusCode
Copy link
Member

Choose a reason for hiding this comment

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

Why copied rather than re-used?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't want to add a dependency on the .NET gRPC library just for this

namespace Temporalio.Exceptions
{
/// <summary>
/// Thrown when a query is rejected by the worker due to bad workflow status.
Copy link
Member

Choose a reason for hiding this comment

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

Worth explicitly distinguishing the difference between this and WorkflowQueryFailedException in the docstring I think

Copy link
Member Author

Choose a reason for hiding this comment

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

Will do! Also noticed a typo here that may help explain the difference too

Suggested change
/// Thrown when a query is rejected by the worker due to bad workflow status.
/// Thrown when a query is rejected by the server due to bad workflow status.

Comment on lines +218 to +219
// TODO(cretz): Ok to use aggregate exception here or should I just
// comma-delimit into a single message or something?
Copy link
Member

Choose a reason for hiding this comment

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

Seems like that's what it's there for

Copy link
Member Author

Choose a reason for hiding this comment

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

Kinda, but it's not "AggregateMessageException", it has separate exceptions carrying their own stack traces, causes, etc. But I agree, probably good enough, and bonus is the outputters know how to format this one well.

var afterNow = DateTime.UtcNow.AddSeconds(30);
var temp = desc.CloseTime!.Value;
Assert.InRange(desc.CloseTime!.Value, beforeNow, afterNow);
Assert.InRange(desc.ExecutionTime!.Value, beforeNow, afterNow);
Copy link
Contributor

@jakejscott jakejscott Jan 27, 2023

Choose a reason for hiding this comment

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

@cretz Not sure if you want to add another dependency, but Fluent Assertions library is alot nicer to use and gives better output when assertions fail.

It has a helpers that let you test a date is CloseTo some time and you pass it a TimeSpan of how close
https://fluentassertions.com/datetimespans/

The object graph comparision also comes in handy
https://fluentassertions.com/objectgraphs/

Also useful is the ability to async retry something and still use assertions in the body (which gives nice errors when it fails)...

Func<Task> asyncRetry = async () =>
{
    var describeExecutionResponse = await _stepFunctions.DescribeExecutionAsync(new DescribeExecutionRequest
    {
        ExecutionArn = executionArn
    });
    describeExecutionResponse.Should().NotBeNull();
    describeExecutionResponse.Status.Should().Be(ExecutionStatus.SUCCEEDED);
};
await asyncRetry.Should().NotThrowAfterAsync(waitTime: 60.Seconds(), pollInterval: 2.Seconds());

Copy link
Member Author

Choose a reason for hiding this comment

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

As the tests grow I very well may add that dependency or other test helpers (I don't mind adding dependencies to our test project). I haven't needed too much yet (and I have started an AssertMore package at the root of the project for a couple of them).

@cretz cretz force-pushed the workflow-client branch 2 times, most recently from 4db827c to 15c66ee Compare January 30, 2023 14:53
@cretz
Copy link
Member Author

cretz commented Jan 30, 2023

This PR has had as much review as it's going to receive I'm afraid. Merging.

@cretz cretz merged commit 468f35d into temporalio:main Jan 30, 2023
@cretz cretz deleted the workflow-client branch January 30, 2023 15:40
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.

3 participants