-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: Move HeaderInterceptor to use our Middleware API
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.
- Loading branch information
Showing
5 changed files
with
169 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Grpc.Core; | ||
using Grpc.Core.Interceptors; | ||
using Momento.Sdk.Config.Middleware; | ||
|
||
namespace Momento.Sdk.Internal.Middleware | ||
{ | ||
class Header | ||
{ | ||
public const string AuthorizationKey = "Authorization"; | ||
public const string AgentKey = "Agent"; | ||
public const string RuntimeVersionKey = "Runtime_Version"; | ||
public readonly List<string> onceOnlyHeaders = new List<string> { Header.AgentKey, Header.RuntimeVersionKey }; | ||
public string Name; | ||
public string Value; | ||
public Header(String name, String value) | ||
{ | ||
this.Name = name; | ||
this.Value = value; | ||
} | ||
} | ||
|
||
class HeaderMiddleware : IMiddleware | ||
{ | ||
private readonly List<Header> headersToAddEveryTime = new List<Header> { }; | ||
private readonly List<Header> headersToAddOnce = new List<Header> { }; | ||
private volatile Boolean areOnlyOnceHeadersSent = false; | ||
public HeaderMiddleware(List<Header> headers) | ||
{ | ||
this.headersToAddOnce = headers.Where(header => header.onceOnlyHeaders.Contains(header.Name)).ToList(); | ||
this.headersToAddEveryTime = headers.Where(header => !header.onceOnlyHeaders.Contains(header.Name)).ToList(); | ||
} | ||
|
||
public async Task<MiddlewareResponseState<TResponse>> WrapRequest<TRequest, TResponse>( | ||
TRequest request, | ||
CallOptions callOptions, | ||
Func<TRequest, CallOptions, Task<MiddlewareResponseState<TResponse>>> continuation | ||
) | ||
{ | ||
var callOptionsWithHeaders = callOptions; | ||
if (callOptionsWithHeaders.Headers == null) | ||
{ | ||
callOptionsWithHeaders = callOptionsWithHeaders.WithHeaders(new Metadata()); | ||
} | ||
|
||
var headers = callOptionsWithHeaders.Headers!; | ||
|
||
foreach (Header header in this.headersToAddEveryTime) | ||
{ | ||
headers.Add(header.Name, header.Value); | ||
} | ||
if (!areOnlyOnceHeadersSent) | ||
{ | ||
foreach (Header header in this.headersToAddOnce) | ||
{ | ||
headers.Add(header.Name, header.Value); | ||
} | ||
areOnlyOnceHeadersSent = true; | ||
} | ||
|
||
|
||
var nextState = await continuation(request, callOptionsWithHeaders); | ||
return new MiddlewareResponseState<TResponse>( | ||
ResponseAsync: nextState.ResponseAsync, | ||
ResponseHeadersAsync: nextState.ResponseHeadersAsync, | ||
GetStatus: nextState.GetStatus, | ||
GetTrailers: nextState.GetTrailers | ||
); | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters