Skip to content

Conversation

@thrau
Copy link
Member

@thrau thrau commented Feb 4, 2024

Motivation

There have been several situations in the recent past where we needed to figure out whether certain issues come from our Gateway or Hypercorn. Because we have no alternative way of serving the gateway other than hypercorn, this is very difficult. This PR does some refactoring and provides a first alternative: a werkzeug dev server, that can be activated by setting GATEWAY_SERVER=werkzeug.

The werkzeug dev server integration for now is mostly for testing/development purposes. With werkzeug there are also some expected test failures (websockets, anything streaming or HTTP2 related). So I wouldn't run a test suite on this regularly. Here's a test run showing the remaining failing tests. AFAICT all those are expected since they involve streaming or websockets, or they are making unnecessarily strict assumptions on headers. The test_s3_get_response_case_sensitive_headers should probably be removed since it uses and old variable from the http2_server.

It can be used to test whether some issues are related to hypercorn or not.

This is not something I would document right now or give to users, but can be useful for us internally for troubleshooting. The underlying refactoring also gives way to serious alternatives like twisted #9834.

Changes

  • The config now has a GATEWAY_SERVER variable that can be set to either hypercorn (default) or werkzeug.
  • LocalStack can now be served through a werkzeug dev server

Testing

start localstack with GATEWAY_SERVER=werkzeug

@github-actions
Copy link

github-actions bot commented Feb 4, 2024

LocalStack Community integration with Pro

    2 files  ±0      2 suites  ±0   1h 25m 46s ⏱️ + 2m 2s
2 657 tests ±0  2 406 ✅ ±0  251 💤 ±0  0 ❌ ±0 
2 659 runs  ±0  2 406 ✅ ±0  253 💤 ±0  0 ❌ ±0 

Results for commit dcfeabe. ± Comparison against base commit 113004c.

♻️ This comment has been updated with latest results.

@thrau thrau added this to the 3.2 milestone Feb 19, 2024
@thrau thrau added the semver: minor Non-breaking changes which can be included in minor releases, but not in patch releases label Feb 23, 2024
@github-actions
Copy link

S3 Image Test Results (AMD64 / ARM64)

  2 files    2 suites   3m 9s ⏱️
387 tests 336 ✅  51 💤 0 ❌
774 runs  672 ✅ 102 💤 0 ❌

Results for commit dcfeabe.

@thrau thrau marked this pull request as ready for review February 24, 2024 16:07
@thrau thrau requested a review from alexrashed February 24, 2024 16:07
@coveralls
Copy link

Coverage Status

coverage: 83.847% (-0.09%) from 83.936%
when pulling dcfeabe on gateway-server
into 113004c on master.

@thrau thrau requested a review from bentsku February 25, 2024 23:15
Copy link
Contributor

@bentsku bentsku left a comment

Choose a reason for hiding this comment

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

Nice! This is looking good and really helpful to debug some issues we have.
Just the thread name of the handler is a bit weird while logging, but other than this minor thing, this looks nice for debugging purposes!

I've ran some benchmarks for fun on it 😅 (in host mode), it worked all right!

run_simple(host, port, WsgiGateway(gateway), use_reloader=use_reloader, **kwargs)


class CustomWSGIRequestHandler(WSGIRequestHandler):
Copy link
Contributor

Choose a reason for hiding this comment

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

q: is there any way to specify the thread name of the threaded handler? Because right now it seems it gives something truncated like:
2024-02-26T17:17:44.123 DEBUG --- [uest_thread)] l.aws.protocol.serializer

Copy link
Member Author

Choose a reason for hiding this comment

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

i looked into it and found that thread creation is controlled by socketserver.ThreadingMixin. This is the code they use:

    def process_request(self, request, client_address):
        """Start a new thread to process the request."""
        if self.block_on_close:
            vars(self).setdefault('_threads', _Threads())
        t = threading.Thread(target = self.process_request_thread,
                             args = (request, client_address))
        t.daemon = self.daemon_threads
        self._threads.append(t)
        t.start()

We could overwrite that, but the question is what to show. A running thread id would continue to increase for each request coming into to system. We could implement a thread pool on top of this actually, but all that seems a bit too much effort right now.

I'll keep it in mind though!

@thrau thrau merged commit c29eaba into master Feb 26, 2024
@thrau thrau deleted the gateway-server branch February 26, 2024 17:57
@thrau thrau mentioned this pull request Mar 5, 2024
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

semver: minor Non-breaking changes which can be included in minor releases, but not in patch releases

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants