-
Notifications
You must be signed in to change notification settings - Fork 33
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
Reserve __temporal prefix #410
Conversation
ec1d8de
to
0d4b240
Compare
0d4b240
to
30229d1
Compare
@@ -47,6 +47,9 @@ dotnet_diagnostic.CA2237.severity = none | |||
# Warn on unused imports | |||
dotnet_diagnostic.IDE0005.severity = warning | |||
|
|||
# Don't warn on using var | |||
dotnet_diagnostic.IDE0008.severity = none |
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.
If you remember, am a bit curious where in code this was triggered
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.
All over. I think it's just a matter of how the default "low" severity shows up in different lang servers. All the low severity stuff shows up in omnisharp, which can be kinda nice to auto fix some stuff sometimes, but, this one is obviously a little silly.
/// This interceptor ensures that handlers using the reserved prefix bypass user | ||
/// interceptors. | ||
/// </summary> | ||
private class InboundReservedPrefixInterceptor : WorkflowInboundInterceptor |
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 do not believe this should be implemented as an interceptor/wrapper that now becomes the outer interceptor always just for this small reason. I believe in ApplyQueryWorkflow
we need to just make the two reserved queries call query logic directly without going through the interceptor. And it is there we should fail if it's reserved and not one of those. Can also fail update and signal in their apply-level places too.
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.
Sure, I did this because it would be robust in the face of different ways to handle built-in operations. If you're not worried about that then I'll get rid of it.
void CheckNamesForPrefix(IEnumerable<string> keys, string type) | ||
{ | ||
foreach (var key in keys) | ||
{ | ||
if (key.StartsWith(Constants.ReservedNamePrefix)) | ||
{ | ||
errs.Add($"{type} handler name {key} cannot start with {Constants.ReservedNamePrefix}"); | ||
} | ||
else if (type == "Query") | ||
{ | ||
foreach (var reservedQ in Workflow.ReservedQueryHandlerPrefixes) | ||
{ | ||
if (key.StartsWith(reservedQ)) | ||
{ | ||
errs.Add($"{type} handler name {key} cannot start with {reservedQ}"); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
CheckNamesForPrefix(signals.Keys, "Signal"); | ||
CheckNamesForPrefix(queries.Keys, "Query"); | ||
CheckNamesForPrefix(updates.Keys, "Update"); |
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 think you can just check signal name prefix in signal definition, update in update definition, and query in query definition. It is clearer to keep validation with the definition. Can just do it in those constructors if you want.
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.
The downside of this is now you need a specific bypassing constructor -- see my last commit
src/Temporalio/Common/Constants.cs
Outdated
/// <summary> | ||
/// Prefix for reserved handler and definition names. | ||
/// </summary> | ||
internal const string ReservedNamePrefix = "__temporal"; |
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.
If you can think of any other class, would be ok moving there (e.g. even TemporalRuntime
since it's internal) instead of a whole new class/file for a single constant.
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.
Well there's always going to be something that'd be the first reason to have a common place for constants - no where else felt like an accurate fit, but I can move it to Runtime.
src/Temporalio/Common/Constants.cs
Outdated
/// <summary> | ||
/// Prefix for reserved handler and definition names. | ||
/// </summary> | ||
internal const string ReservedNamePrefix = "__temporal"; |
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.
Technically __temporal_
, but I am ok with this without trailing underscore
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 think we should probably actually make it specifically be without that. Seems very odd you could register __temporalmything
but not __temporal_mything
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.
Yeah, was unsure here because in spec I added underscore not thinking and other SDKs already merged theirs, though I doubt an inconsistency here matters.
e59ee58
to
4ecc6c5
Compare
queryDefn = WorkflowQueryDefinition.CreateWithoutAttributeReservedName( | ||
"__stack_trace", getter); | ||
} | ||
else if (query.QueryType == "__temporal_workflow_metadata") | ||
{ | ||
Func<Api.Sdk.V1.WorkflowMetadata> getter = GetWorkflowMetadata; | ||
queryDefn = WorkflowQueryDefinition.CreateWithoutAttribute( | ||
queryDefn = WorkflowQueryDefinition.CreateWithoutAttributeReservedName( |
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.
For these two, we need to not go through interceptors to invoke them. Would be ok if they aren't even "query definitions" and just invoked directly or something (also saves you from having that bypass constructor param for query definition)
{ | ||
if (!bypassReserved && name != null) |
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.
If you want to save lines, add using System.Linq;
import and then:
if (!bypassReserved && name != null) | |
if (!bypassReserved && name != null && ReservedQueryHandlerPrefixes.Any(p => name.StartsWith(p)) |
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.
Don't save all that much if you want to keep the prefix name in the error which I do, but, changed.
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.
LGTM, one minor change about removing constructor param
private static readonly ConcurrentDictionary<MethodInfo, WorkflowQueryDefinition> MethodDefinitions = new(); | ||
private static readonly ConcurrentDictionary<PropertyInfo, WorkflowQueryDefinition> PropertyDefinitions = new(); | ||
|
||
private WorkflowQueryDefinition(string? name, string? description, MethodInfo? method, Delegate? del) | ||
private WorkflowQueryDefinition(string? name, string? description, MethodInfo? method, Delegate? del, bool bypassReserved = false) |
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.
Can you now remove this constructor parameter for bypassing since it is never true 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.
Woops, thanks
ccf3354
to
0f9795b
Compare
0f9795b
to
ac0697d
Compare
/// <summary> | ||
/// Prefix for reserved handler and definition names. | ||
/// </summary> | ||
internal const string ReservedNamePrefix = "__temporal"; |
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.
Shouldn't it be __temporal_
per temporalio/features#576
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.
See up here: #410 (comment)
Yeah, that's what's written there, but, also that just seems wrong. Probably we should change that spec.
What was changed
See temporalio/features#576
Why?
Future flexibility for us to implement built-in handlers
Checklist
Closes [Feature Request] Special behavior for Temporal built-in prefixes #391
How was this tested:
New tests & test upgrades
Any docs updates needed?