-
-
Notifications
You must be signed in to change notification settings - Fork 4k
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
POC of global tables version 2019 #6744
Conversation
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.
eager to get this into v1.1, but i have some concerns about the context modification that i would like to get an extra opinion on first, ideally @alexrashed
# modify the context to query the original region where the table has been created | ||
context.region = region |
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.
modifying the request context this way can lead to unexpected behavior downstream in the handler chain. i'm not sure it will really be a problem. maybe it would be better to create a fresh request context and make a completely new request transparently to the client. but then the response would contain a region that's different to the original request, which may be equally problematic 🤷
i guess we can live with it for now. any maybe @alexrashed has some thoughts about 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.
I don't think it causes problems directly, but I do agree that these properties of the context should be somewhat immutable.
Imho, these modifications should be handled by creating a new context which is only created for the forwarding.
In fact, the ForwardingFallbackDispatcher
already creates a separate context for the request forwarding (in most cases):
localstack/localstack/aws/forwarder.py
Lines 70 to 79 in 4a58a97
if service_request is not None: | |
local_context = create_aws_request_context( | |
service_name=context.service.service_name, | |
action=context.operation.name, | |
parameters=service_request, | |
region=context.region, | |
) | |
local_context.request.headers.update(context.request.headers) | |
context = local_context | |
return forward_request(context, forward_url_getter) |
So the cleanest way would be to refactor the forwarding such that it becomes a bit more flexible, but currently the context modification should not cause any issues.
7acdd3b
to
a78a33a
Compare
a78a33a
to
cc987cd
Compare
Co-authored-by: Thomas Rausch <thomas@thrau.at>
cc987cd
to
88fb753
Compare
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.
hey @giograno, thanks for considering my comments! i think this is heading in a good direction, and i think in principle the idea of having a modifier is a good idea!
i remembered that i had built something similar in ext (you can find it in the batch provider), that looks something like this:
@contextmanager
def modified_headers(request: Request, headers: Union[Mapping, Headers]):
"""
Context manager that extends the original headers of the HTTP request with the given headers in-place. When the
context manager exits, the original headers are restored.
TODO: move to localstack.http
:param request: the request to modify
:param headers: the modified headers
:return: a context manager that returns the request context
"""
original = request.headers
modified = Headers()
modified.update(original)
modified.update(headers)
request.headers = modified
yield request
request.headers = original
which i then call
with modified_headers(context.request, headers):
LOG.info("submitting job %s", request)
return call_moto_with_request(context, request)
maybe we can slightly adapt and repurpose this idea to the particular case of dynamodb. i think a context manager that modifies the original context, makes the request, but then undoes the modifications (rather than copying the request) would be a great compromise.
also, i think it would be good to keep the code in dynamodb for now until situations emerge where we can re use the code.
i hope you find the review constructive, happy to help with the changes of you want!
localstack/aws/forwarder.py
Outdated
self.region = region | ||
|
||
def modify_context(self, context: RequestContext) -> RequestContext: | ||
_context = copy.copy(context) |
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.
copying the request context like this is not safe. the context contains the original http request object, which has all sorts of IO internals that may break in unexpected ways when copying. so i would avoid any pattern that relies on copying the context all together.
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.
looks great now! thanks for considering all the comments :-)
This PR introduces initial support for DynamoDB global tables version 2019.
We simulate replicas as follows:
PutItem
andGetItem
at the moment) on the created global table from other regions. Before forwarding the call to DDB local, we inspect our cross-region attribute to see if this is a global table and if in the current regions there is a valid replica. If so, we change the context of the call and the credentials in the header to perform a call against the original region (where the table effectively lives) and not to the replica (DDB local won't find it).Such an approach is still rudimental and probably it does not cover a lot of corner cases, but we are able to replicate the example in the docs in an integration test.