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 usage of a single object instances for multiple concurrent requests #70

Closed
wants to merge 5 commits into from

Conversation

dfangl
Copy link
Member

@dfangl dfangl commented Aug 31, 2023

Motivation

Currently, for the following services:

amp
apigateway
apigatewayv2
appconfig
appsync
awslambda
cloudfront
cognitoidp
databrew
ebs
elastictranscoder
glacier
greengrass
guardduty
instance_metadata
iot
managedblockchain
mq
pinpoint
quicksight
route53
s3
s3control
eventbridgescheduler

we use a single instance of the respective ...Response class to handle all the requests.

In LocalStack, this leads to issues with parallel requests influencing each others state, most notably of region and account.

There are a couple of different ways to fix this, we chose one that was minimally intrusive to the existing logic, but ensured a separate instance of the Response class for every request.

Unaffected services use the dispatch method. There are some services which use the classmethod dispatch on an instance, but since that does not make a difference (even though it can be confusing), we did not change it with this PR.

Changes

  • Create method_dispatch class method in the BaseResponse class, which will take an unbound function as input, and execute the corresponding method on a new instance on the class. This ensures proper typing and having the type checker catch potential errors, while being able to keep the current pattern of dispatching.
  • Refactor affected services to use this new function instead of calling a method on a singleton instance of the Response class.
  • Some minor typing changes to avoid typing errors

Comment on lines 237 to 253
@classmethod
def method_dispatch( # type: ignore[misc]
cls, to_call: Callable[[ResponseShape, Any, str, Any], TYPE_RESPONSE]
) -> Callable[[Any, str, Any], TYPE_RESPONSE]:
"""
Takes a given unbound function (part of a Response class) and executes it for a new instance of this
response class.
Can be used wherever we want to specify different methods for dispatching in urls.py
:param to_call: Unbound method residing in this Response class
:return: A wrapper executing the given method on a new instance of this class
"""

def _inner(request: Any, full_url: str, headers: Any) -> TYPE_RESPONSE:
return getattr(cls(), to_call.__name__)(request, full_url, headers)

return _inner

Copy link
Member Author

Choose a reason for hiding this comment

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

This is the main logic used for this change.

:return: A wrapper executing the given method on a new instance of this class
"""

@functools.wraps(to_call) # type: ignore
Copy link
Member Author

Choose a reason for hiding this comment

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

This is currently needed to pass the test test_core.test_server.test_domain_dispatched_with_service (with modifications). It not really wraps the method completely, so this should be discussed.

@dfangl
Copy link
Member Author

dfangl commented Aug 31, 2023

Merged upstream in getmoto#6746

@dfangl dfangl closed this Aug 31, 2023
@dfangl dfangl deleted the fix-response-singletons branch August 31, 2023 22:05
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.

1 participant