-
Notifications
You must be signed in to change notification settings - Fork 33
Added Counter Interceptor Sample #77
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
Changes from 8 commits
d678366
f428229
26fdbee
c68e75d
ec9da55
31c0743
ca90698
7ac67a9
34c83af
7682937
37692a7
d548089
d113bd3
c0131fd
4557ffe
c7b6e31
f3a82cc
078bbe6
fc4fada
c6f5e55
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,87 @@ | ||||||||||||||||||||||||
| namespace TemporalioSamples.CounterInterceptor; | ||||||||||||||||||||||||
| public record ClientCounts | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
| { | ||||||||||||||||||||||||
| public uint Executions { get; internal set; } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| public uint Signals { get; internal set; } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| public uint Queries { get; internal set; } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| public override string ToString() | ||||||||||||||||||||||||
| { | ||||||||||||||||||||||||
| return | ||||||||||||||||||||||||
| "\n\tTotal Number of Workflow Exec: " + Executions + | ||||||||||||||||||||||||
| "\n\tTotal Number of Signals: " + Signals + | ||||||||||||||||||||||||
| "\n\tTotal Number of Queries: " + Queries; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
| public override string ToString() | |
| { | |
| return | |
| "\n\tTotal Number of Workflow Exec: " + Executions + | |
| "\n\tTotal Number of Signals: " + Signals + | |
| "\n\tTotal Number of Queries: " + Queries; | |
| } | |
| public override string ToString() => | |
| $"\n\tTotal Number of Workflow Exec: {Executions}\n\t" + | |
| $"Total Number of Signals: {Signals}\n\tTotal Number of Queries: {Queries}"; | |
| } |
Can break up long line, but might as well use interpolation, and might as well use => for single-line methods. Granted, despite what I said before, using ToString() for multiline strings only for a specific scenario is a bit much, but fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why have this separate class? Why not just use Dictionary<string, ClientCounts> where it's needed? Do not use static state, store the dictionary on the interceptor and make it available to the creator of the interceptor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use => for single-line methods
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
rross marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,19 @@ | ||||||||||||
| namespace TemporalioSamples.CounterInterceptor; | ||||||||||||
|
|
||||||||||||
| using System.Diagnostics; | ||||||||||||
| using Temporalio.Activities; | ||||||||||||
|
|
||||||||||||
| public class MyActivities | ||||||||||||
| { | ||||||||||||
| [Activity] | ||||||||||||
| public string SayHello(string name, string title) | ||||||||||||
| { | ||||||||||||
| return "Hello " + title + " " + name; | ||||||||||||
| } | ||||||||||||
|
||||||||||||
| public string SayHello(string name, string title) | |
| { | |
| return "Hello " + title + " " + name; | |
| } | |
| public string SayHello(string name, string title) => $"Hello {title} {name}"; |
Use string interpolation and single-statement syntax (will stop commenting on this, but it applies project wide)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bump, this was not addressed
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are inconsistent with your single-line methods, this should be => like the one just above it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| namespace TemporalioSamples.CounterInterceptor; | ||
|
|
||
| using Temporalio.Workflows; | ||
|
|
||
| [Workflow] | ||
| public class MyChildWorkflow | ||
| { | ||
| private readonly ActivityOptions activityOptions = new() | ||
| { | ||
| StartToCloseTimeout = TimeSpan.FromSeconds(10), | ||
| }; | ||
|
|
||
| [WorkflowRun] | ||
| public async Task<string> RunAsync(string name, string title) => | ||
| await Workflow.ExecuteActivityAsync((MyActivities act) => act.SayHello(name, title), activityOptions) + | ||
| await Workflow.ExecuteActivityAsync((MyActivities act) => act.SayGoodBye(name, title), activityOptions); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| namespace TemporalioSamples.CounterInterceptor; | ||
|
|
||
| using Temporalio.Workflows; | ||
|
|
||
| [Workflow] | ||
| public class MyWorkflow | ||
| { | ||
| private bool exit; // Automatically defaults to false | ||
|
|
||
| [WorkflowRun] | ||
| public async Task<string> RunAsync() | ||
| { | ||
| // Wait for greeting info | ||
| await Workflow.WaitConditionAsync(() => Name != null && Title != null); | ||
|
||
|
|
||
| // Execute Child Workflow | ||
| var result = await Workflow.ExecuteChildWorkflowAsync( | ||
| (MyChildWorkflow wf) => wf.RunAsync(Name, Title), | ||
| new() { Id = "counter-interceptor-child" }); | ||
|
|
||
| // Wait for exit signal | ||
| await Workflow.WaitConditionAsync(() => exit); | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| [WorkflowSignal] | ||
| public async Task SignalNameAndTitleAsync(string name, string title) | ||
| { | ||
| Name = name; | ||
| Title = title; | ||
| } | ||
|
|
||
| [WorkflowQuery] | ||
| public string Name { get; private set; } = string.Empty; | ||
|
|
||
| [WorkflowQuery] | ||
| public string Title { get; private set; } = string.Empty; | ||
|
|
||
| [WorkflowSignal] | ||
| public async Task ExitAsync() => exit = true; | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,84 @@ | ||||||||||
| namespace TemporalioSamples.CounterInterceptor; | ||||||||||
|
|
||||||||||
| using Temporalio.Client; | ||||||||||
| using Temporalio.Worker; | ||||||||||
|
|
||||||||||
| internal class Program | ||||||||||
| { | ||||||||||
| private static async Task Main(string[] args) | ||||||||||
| { | ||||||||||
| var client = await TemporalClient.ConnectAsync( | ||||||||||
| options: new("localhost:7233") | ||||||||||
| { | ||||||||||
| Interceptors = new[] | ||||||||||
| { | ||||||||||
| new SimpleClientCallsInterceptor(), | ||||||||||
|
||||||||||
| }, | ||||||||||
| }); | ||||||||||
|
|
||||||||||
| using var tokenSource = new CancellationTokenSource(); | ||||||||||
| Console.CancelKeyPress += (_, eventArgs) => | ||||||||||
|
||||||||||
| { | ||||||||||
| tokenSource.Cancel(); | ||||||||||
| eventArgs.Cancel = true; | ||||||||||
| }; | ||||||||||
|
|
||||||||||
| var activities = new MyActivities(); | ||||||||||
|
|
||||||||||
| var taskQueue = "CounterInterceptorTaskQueue"; | ||||||||||
|
|
||||||||||
| var workerOptions = new TemporalWorkerOptions(taskQueue). | ||||||||||
| AddAllActivities(activities). | ||||||||||
| AddWorkflow<MyWorkflow>(). | ||||||||||
| AddWorkflow<MyChildWorkflow>(); | ||||||||||
|
|
||||||||||
| workerOptions.Interceptors = new[] { new SimpleCounterWorkerInterceptor() }; | ||||||||||
|
||||||||||
|
|
||||||||||
| using var worker = new TemporalWorker( | ||||||||||
| client, | ||||||||||
| workerOptions); | ||||||||||
|
|
||||||||||
| // Run worker until cancelled | ||||||||||
| Console.WriteLine("Running worker..."); | ||||||||||
| try | ||||||||||
| { | ||||||||||
| // Start the workers | ||||||||||
| var workerResult = worker.ExecuteAsync(tokenSource.Token); | ||||||||||
|
|
||||||||||
| // Start the workflow | ||||||||||
| var handle = await client.StartWorkflowAsync( | ||||||||||
| (MyWorkflow wf) => wf.RunAsync(), | ||||||||||
| new(id: Guid.NewGuid().ToString(), taskQueue: taskQueue)); | ||||||||||
|
|
||||||||||
| Console.WriteLine("Sending name and title to workflow"); | ||||||||||
| await handle.SignalAsync(wf => wf.SignalNameAndTitleAsync("John", "Customer")); | ||||||||||
|
|
||||||||||
| var name = await handle.QueryAsync(wf => wf.Name); | ||||||||||
| var title = await handle.QueryAsync(wf => wf.Title); | ||||||||||
|
|
||||||||||
| // Send exit signal to workflow | ||||||||||
| await handle.SignalAsync(wf => wf.ExitAsync()); | ||||||||||
|
|
||||||||||
| var result = await handle.GetResultAsync(); | ||||||||||
|
|
||||||||||
| Console.WriteLine($"Workflow result is {result}", result); | ||||||||||
|
||||||||||
| Console.WriteLine($"Workflow result is {result}", result); | |
| Console.WriteLine($"Workflow result is {result}"); |
or
| Console.WriteLine($"Workflow result is {result}", result); | |
| Console.WriteLine($"Workflow result is {0}", result); |
But not both. This mistake is made in other lines below. Probably the former approach is best.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bump this was never addressed. If you are using interpolation, you don't also pass as a param.
rross marked this conversation as resolved.
Show resolved
Hide resolved
|
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,28 @@ | ||||||||||||||
| # dotnet-counter-interceptor | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not really the best title, but that's ok |
||||||||||||||
| The sample demonstrates: | ||||||||||||||
| - the use of a Worker Workflow Interceptor that counts the number of Workflow Executions, Child Workflow Executions, and Activity Executions and the number of Signals and Queries. It is based | ||||||||||||||
| off of the [Java sample](https://github.com/temporalio/samples-java/tree/main) located [here](https://github.com/temporalio/samples-java/tree/main/core/src/main/java/io/temporal/samples/countinterceptor) | ||||||||||||||
| - the use of a Client Workflow Interceptor that counts the number of Workflow Executions and the number of Signals and Queries. | ||||||||||||||
|
|
||||||||||||||
| ## Start local Temporal Server | ||||||||||||||
| ```bash | ||||||||||||||
| # run only once | ||||||||||||||
| temporal server start-dev | ||||||||||||||
| ``` | ||||||||||||||
|
||||||||||||||
| ## Start local Temporal Server | |
| ```bash | |
| # run only once | |
| temporal server start-dev | |
| ``` | |
| To run, first see [README.md](https://github.com/temporalio/samples-dotnet/blob/main/README.md) for prerequisites |
We like to keep the starting of the local server in one place since it can change and there are multiple options. This can be seen in other samples. (in fact, we will make these run easy on cloud too soon, so we don't want to have to come back and update these)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bump, this was never addressed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bump again, this is still not addressed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Finally addressed :)
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is more than the worker, it's the worker and the client calls mixed into one. Many samples split these, but don't have to here, but it's not just "worker" as the title suggests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bump, this was never addressed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bump again, this is still not addressed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this section applies anymore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bump, this was never addressed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deleted.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,59 @@ | ||||||
| namespace TemporalioSamples.CounterInterceptor; | ||||||
|
|
||||||
| using Temporalio.Client; | ||||||
| using Temporalio.Client.Interceptors; | ||||||
|
|
||||||
| public class SimpleClientCallsInterceptor : IClientInterceptor | ||||||
|
||||||
| { | ||||||
| private ClientCounter clientCounter; | ||||||
|
||||||
| private ClientCounter clientCounter; | |
| private readonly ClientCounter clientCounter = new(); |
And get rid of the constructor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bump
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then can remove this method entirely
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider just using input.Options.Id ?? "<none>" where string is optional. And you don't even need this for query and others where ID is always present. No need for this extra method probably
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bump, only three places have this, no need to make a whole new method for a simple id ?? "None" in those three places
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A bit surprised this passes CI, maybe we don't have a
dotnet formatcheck. Usually we want there to be a blank line between namespace declaration and type declarataionThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.