-
Notifications
You must be signed in to change notification settings - Fork 2
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
Add operation interceptors #14
Add operation interceptors #14
Conversation
Here is an example of how these interceptors would be used temporalio/sdk-java#2278 |
bc96d00
to
c8881f8
Compare
public interface OperationMiddleware { | ||
|
||
/** Intercepts the given operation. Called once for each operation invocation. */ | ||
OperationHandler<Object, Object> intercept(OperationHandler<Object, Object> next); |
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.
@cretz I know one of your desires was to allow the interceptor to switch on different operations, right now that is possible inside the wrapped OperationHandler
, we could also add a OperationContext
as the first parameter here.
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.
Yes, but I also wonder if that's enough for future proofing if we wanted to add something else. Maybe a OperationMiddlewareInterceptContext
that contains the operation context and maybe even this next
handler (though I'd be ok if they remained separate parameters). Or could just be an inner class of Context
here. Also, I wonder if people should be allowed to alter the input information passed to the next middleware similar to how one might in Temporal interceptors today.
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.
wonder if people should be allowed to alter the input information passed to the next middleware similar to how one might in Temporal interceptors today.
That is already possible with this implementation in the exact same way
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 address the earlier part of the paragraph about adding some kind of contextual object even if it's empty or mostly empty today? As for altering the values, so long as nobody expects to alter the operation name itself, agreed.
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.
Yes, but I also wonder if that's enough for future proofing if we wanted to add something else.
I think if we want to add anything that is common across all operation methods it would go in the OperationContext
, if it specific to a certain method like start then the wrapped handler should deal with 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.
@bergundy if you have any thoughts here
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 agree we can supply some context here. It would contain the service name, operation name, and request header. The rest of the information is method specific, and IMHO, should be intercepted by the wrapped handler.
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 obvious downside for instantiating these handlers per request is the extra garbage generated but I'm not too concerned with that.
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.
OK added context
as a first parameter
@@ -53,7 +53,7 @@ import com.vanniktech.maven.publish.SonatypeHost | |||
mavenPublishing { | |||
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) | |||
|
|||
signAllPublications() |
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.
Note: need to remove this before merging, this line just makes local development impossible
@@ -87,7 +103,7 @@ public HandlerResultContent fetchOperationResult( | |||
if (handler == null) { | |||
throw newUnrecognizedOperationException(context.getService(), context.getOperation()); | |||
} | |||
Object result = handler.fetchResult(context, details); | |||
Object result = getOperationHandler(handler).fetchResult(context, details); |
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 we did https://github.com/nexus-rpc/sdk-java/pull/14/files#r1855645828 we could also consider switching where we call getOperationHandler
to be before the data coversion. This would allow to fail requests before the data converter runs.
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, that'd be great.
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, this only applied to start
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 only minor things
public interface OperationMiddleware { | ||
|
||
/** Intercepts the given operation. Called once for each operation invocation. */ | ||
OperationHandler<Object, Object> intercept(OperationHandler<Object, Object> next); |
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.
Yes, but I also wonder if that's enough for future proofing if we wanted to add something else. Maybe a OperationMiddlewareInterceptContext
that contains the operation context and maybe even this next
handler (though I'd be ok if they remained separate parameters). Or could just be an inner class of Context
here. Also, I wonder if people should be allowed to alter the input information passed to the next middleware similar to how one might in Temporal interceptors today.
nexus-sdk/src/main/java/io/nexusrpc/handler/ServiceHandler.java
Outdated
Show resolved
Hide resolved
public interface OperationMiddleware { | ||
|
||
/** Intercepts the given operation. Called once for each operation invocation. */ | ||
OperationHandler<Object, Object> intercept(OperationHandler<Object, Object> next); |
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.
OperationHandler<Object, Object> intercept(OperationHandler<Object, Object> next); | |
OperationHandler<Object, Object> apply(OperationHandler<Object, Object> next); |
I wonder if we don't need to call this "intercept" or these "interceptors" if we're adopting middleware-ish terminology. But I don't mind intercept
either.
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.
Maybe wrap
? But intercept
also works for me.
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.
Left as intercept
for now
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.
Agree we should add the context and allow intercepting before deserializing the input.
public interface OperationMiddleware { | ||
|
||
/** Intercepts the given operation. Called once for each operation invocation. */ | ||
OperationHandler<Object, Object> intercept(OperationHandler<Object, Object> next); |
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 agree we can supply some context here. It would contain the service name, operation name, and request header. The rest of the information is method specific, and IMHO, should be intercepted by the wrapped handler.
public interface OperationMiddleware { | ||
|
||
/** Intercepts the given operation. Called once for each operation invocation. */ | ||
OperationHandler<Object, Object> intercept(OperationHandler<Object, Object> next); |
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.
Maybe wrap
? But intercept
also works for me.
public interface OperationMiddleware { | ||
|
||
/** Intercepts the given operation. Called once for each operation invocation. */ | ||
OperationHandler<Object, Object> intercept(OperationHandler<Object, Object> next); |
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 obvious downside for instantiating these handlers per request is the extra garbage generated but I'm not too concerned with that.
@@ -87,7 +103,7 @@ public HandlerResultContent fetchOperationResult( | |||
if (handler == null) { | |||
throw newUnrecognizedOperationException(context.getService(), context.getOperation()); | |||
} | |||
Object result = handler.fetchResult(context, details); | |||
Object result = getOperationHandler(handler).fetchResult(context, details); |
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, that'd be great.
nexus-sdk/src/test/java/io/nexusrpc/handler/ServiceHandlerTest.java
Outdated
Show resolved
Hide resolved
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, only minor things
nexus-sdk/src/main/java/io/nexusrpc/handler/ServiceHandler.java
Outdated
Show resolved
Hide resolved
nexus-sdk/src/main/java/io/nexusrpc/handler/ServiceHandler.java
Outdated
Show resolved
Hide resolved
d2134b4
to
2660bba
Compare
Based of the internal proposed interface. See the test case for two example middlewares that are possible with this interface