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

fix: Move HeaderInterceptor to use our Middleware API #281

Merged
merged 2 commits into from
Oct 7, 2022

Conversation

cprice404
Copy link
Contributor

Prior to this commit, we had a gRPC Interceptor that was
responsible for setting headers (cache name, auth token, etc.)
that were sent to the server.

We attempted to implement our Middleware layer using gRPC interceptors
but because their API is not asynchronous, there was no way to
accomplish the asynchronous tasks that we needed to accomplish,
so we had to introduce a bespoke layer for our Middleware that uses
the same patterns and some of the same constructs as the gRPC
Interceptors do, but which supported an asynchronous API.

This left us with a mix of both Interceptors (for the Header Interceptor)
and Middlewares. This proved to be problematic when attempting to
implement request retries, because we could not control the order that
the interceptor ran in relative to the middlewares. Thus whenever
we were executing our retry logic, the header interceptor would be
re-run and it would add a second copy of all of the headers, which
made the request invalid.

It's important that we be able to exercise full control over the
order that all of the middlewares are executed, so in this PR
we migrate the Header Interceptor over to be a Middleware instead.
This allows us to position it in the correct spot in the ordered
list of Middlewares.

Because the control plane client was also using the Headers interceptor,
this commit also adds Middleware support for the control plane client
and migrates it from the old Headers Interceptor to the new Headers
Middleware.

@cprice404 cprice404 force-pushed the migrate-header-interceptor-to-middleware branch from 96f6df7 to 963378f Compare October 7, 2022 00:15
@cprice404 cprice404 changed the base branch from main to handle-continuation-exception-types October 7, 2022 00:16
@cprice404 cprice404 force-pushed the migrate-header-interceptor-to-middleware branch 2 times, most recently from c215338 to 3d5ef7c Compare October 7, 2022 00:32
pgautier404
pgautier404 previously approved these changes Oct 7, 2022
Copy link
Contributor

@kvcache kvcache left a comment

Choose a reason for hiding this comment

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

Overall idea seems fine. Couple smaller questions

Comment on lines +39 to 41
public ILoggerFactory? LoggerFactory { get; }

public IMiddleware WithLoggerFactory(ILoggerFactory loggerFactory);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do these live on IMiddleware instead of being concerns of the implementation? Conceptually, a LoggerFactory getter seems orthogonal to the job of an IMiddleware, as advertised by its interface.

Copy link
Contributor Author

@cprice404 cprice404 Oct 7, 2022

Choose a reason for hiding this comment

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

The Configuration object is where a user defines their logging configuration.

The user may also pass in a list of Middlewares and I don't want or need them to have to also pass in the logging config to each and every one of those Middlewares.

Therefore the Configuration object needs to be able to loop over the middlewares and configure their logging, if the user didn't explicitly add a logging config to the middleware.

Therefore the IMiddleware interface must expose a way for the Configuration to get/set their logging configuration.

Copy link
Contributor

Choose a reason for hiding this comment

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

The Configuration object is where a user defines their logging configuration.

Sure, so shouldn't middleware implementations which consume Configuration either take in Configuration or their relevant explicit Configuration dependencies in their constructors?

if the user didn't add logging, then why does their middleware need logging configuration? For middleware-framework logging it seems like you'd want a middleware-framework logger instance, no? And for middleware-implementation logging, if you don't log then why should there be an interface dependency?

I think this pattern (migrating from ILoggerFactory to ILoggerFactory?) is mixing setter-injection and constructor-injection. It's unclear to me how setter-injection is made appropriate or necessary by this pr. Maybe we should chat or zoom separately

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Discussed this with Kenny offline. I agree there's some code smell on this and we talked through a few ideas to experiment with. The scope of those changes is bigger than appropriate for this PR so I am going to try to find some time to look at that separately later today.

return await wrapped.ResponseAsync;
}

private async Task<MiddlewareResponseState<TResponse>> WrapWithMiddleware<TRequest, TResponse>(
Copy link
Contributor

Choose a reason for hiding this comment

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

This function looks completely independent from this class other than this._middlewares. Is it copypasted from somewhere else? Would you like to instead move this function to be an extension on IList<IMiddleware>?

edit: yup, appears to be copypasted from DataGrpcManager. Can you DRY instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 1899667

Base automatically changed from handle-continuation-exception-types to main October 7, 2022 18:50
Prior to this commit, we had a gRPC Interceptor that was
responsible for setting headers (cache name, auth token, etc.)
that were sent to the server.

We attempted to implement our Middleware layer using gRPC interceptors
but because their API is not asynchronous, there was no way to
accomplish the asynchronous tasks that we needed to accomplish,
so we had to introduce a bespoke layer for our Middleware that uses
the same patterns and some of the same constructs as the gRPC
Interceptors do, but which supported an asynchronous API.

This left us with a mix of both Interceptors (for the Header Interceptor)
and Middlewares.  This proved to be problematic when attempting to
implement request retries, because we could not control the order that
the interceptor ran in relative to the middlewares.  Thus whenever
we were executing our retry logic, the header interceptor would be
re-run and it would add a second copy of all of the headers, which
made the request invalid.

It's important that we be able to exercise full control over the
order that all of the middlewares are executed, so in this PR
we migrate the Header Interceptor over to be a Middleware instead.
This allows us to position it in the correct spot in the ordered
list of Middlewares.

Because the control plane client was also using the Headers interceptor,
this commit also adds Middleware support for the control plane client
and migrates it from the old Headers Interceptor to the new Headers
Middleware.
@cprice404
Copy link
Contributor Author

rebased, now will add a commit to address Kenny's DRY comment.

@cprice404 cprice404 force-pushed the migrate-header-interceptor-to-middleware branch from a88d690 to 1899667 Compare October 7, 2022 20:04
Copy link
Contributor

@kvcache kvcache left a comment

Choose a reason for hiding this comment

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

l'sgtm

@cprice404 cprice404 merged commit dfdf72b into main Oct 7, 2022
@cprice404 cprice404 deleted the migrate-header-interceptor-to-middleware branch October 7, 2022 20:24
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