Skip to content

mobile: support handling requests on worker thread#44295

Open
danzh2010 wants to merge 23 commits intoenvoyproxy:mainfrom
danzh2010:mobileworkerthread2
Open

mobile: support handling requests on worker thread#44295
danzh2010 wants to merge 23 commits intoenvoyproxy:mainfrom
danzh2010:mobileworkerthread2

Conversation

@danzh2010
Copy link
Copy Markdown
Contributor

@danzh2010 danzh2010 commented Apr 6, 2026

Commit Message: add a config knob threading_model in ApiListenerManager. And add an interface enableWorkerThread() in C++ and python EngineBuilder to allow choosing a threading model for mobile engine. In addition to the exiting MAIN_THREAD_ONLY model mostly used for mobile deployment, this PR introduces a STANDALONE_WORKER_THREAD model which will drive http requests in a standalone worker thread. This allows E-M to be more like Envoy which also run HTTP listeners and xDS processing on different threads so that network events won't be blocked by xDS config updates.

Note that in STANDALONE_WORKER_THREAD mode certificates validation offloading and system proxy setting is NOT supported as this threading model is not meant to be used by mobile applications.

Risk Level: low, behind knobs
Testing: existing integration tests pass
Docs Changes: N/A
Release Notes: N/A

…pdate tests

Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
…performance

Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
…ly and update tests'

Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
@repokitteh-read-only
Copy link
Copy Markdown

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to (api/envoy/|docs/root/api-docs/).
envoyproxy/api-shepherds assignee is @markdroth
CC @envoyproxy/api-watchers: FYI only for changes made to (api/envoy/|docs/root/api-docs/).

🐱

Caused by: #44295 was opened by danzh2010.

see: more, trace.

@danzh2010 danzh2010 changed the title mobile: support running requests on worker thread mobile: support handling requests on worker thread Apr 6, 2026
Signed-off-by: Dan Zhang <danzh@google.com>
@danzh2010
Copy link
Copy Markdown
Contributor Author

/assign @paul-r-gall

… of client_.

Signed-off-by: Dan Zhang <danzh@google.com>
…Change ASSERT to RELEASE_ASSERT in ApiListenerManagerImpl::httpClient() to ensure it's checked in opt builds.\n- Add info log when worker thread is started.\n- Comment out trace log level setting in rtds_integration_test.cc.\n- Format client_test.cc.

Signed-off-by: Dan Zhang <danzh@google.com>
@@ -458,4 +458,14 @@ message ValidationListenerManager {
// Listener Manager via the bootstrap's :ref:`listener_manager <envoy_v3_api_field_config.bootstrap.v3.Bootstrap.listener_manager>`.
// [#not-implemented-hide:]
message ApiListenerManager {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why is this message in this file to begin with, rather than being in bootstrap.proto? It seems like this wouldn't ever be used outside of the bootstrap, so it doesn't really belong with the rest of the xDS API.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

My guess is that all the listener manager extensions go into this file.

message ApiListenerManager {
enum ThreadingModel {
// Handle HTTP requests on the main Envoy thread which also processes platform-raised events and runs xDS clients.
MainThreadOnly = 0;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Protobuf enum elements should be in all-caps, like MAIN_THREAD_ONLY.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Signed-off-by: Dan Zhang <danzh@google.com>
@danzh2010
Copy link
Copy Markdown
Contributor Author

/retest

Signed-off-by: Dan Zhang <danzh@google.com>
@danzh2010
Copy link
Copy Markdown
Contributor Author

This is ready for review!
/assign @abeyad

@phlax
Copy link
Copy Markdown
Member

phlax commented Apr 14, 2026

@abeyad i think this is waiting on your sign off

@danzh2010
Copy link
Copy Markdown
Contributor Author

friendly ping?

Copy link
Copy Markdown
Contributor

@abeyad abeyad left a comment

Choose a reason for hiding this comment

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

thanks @danzh2010 !

Comment thread mobile/library/cc/engine_builder.cc Outdated
return *this;
}

EngineBuilder& EngineBuilder::enableEarlyData(bool early_data_on) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why are early data changes in this PR?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Some tests accidentally enable early data due to turning off cert validation offloading in some test combination. And early data request doesn't have ssl_start_time populated in final_stream_intel which breaks test assumption. But I figured out another way to bypass the validation. So I reverted early data related change.

Comment thread mobile/library/cc/engine_builder.cc Outdated

#if defined(__APPLE__)
if (respect_system_proxy_settings_) {
if (respect_system_proxy_settings_ && !use_worker_thread_) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

are we using "no separate worker thread" here to mean "not mobile"? I think that would be a dangerous assumption. For non-mobile use cases, respect_system_proxy_settings_ should be set to false anyway.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

"no separate worker thread" means "mobile". Or I should say we only allow respect_system_proxy_settings_ when "no separate worker thread" otherwise the knob is no-op.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not sure why we check both here though. We should only check respect_system_proxy_settings_. If we think it's related, when we set "enableStandaloneWorkerThread()", we should also set respect_system_proxy_settings_ to false there, but I don't even think we need to do that. Unless I'm misunderstanding?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The check here just enforces these 2 knobs won't take effect at the same time if a user misconfigured the builder. The knobs can be called in any sequence on the builder, so if we want to enforce this in the setter, we need to do it in both setters. I slightly prefer adding some enforcement somehow otherwise the Engine can still run but will run into data race?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

WDYT on this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I agree with preventing the system proxy settings from being invoked unless it's on mobile. I'm concerned that the code is very confusing as to why it checks if a worker thread is enabled or not when deciding whether to register the apple system proxy settings.

Ideally, this would be solved by different EngineBuilders for Envoy "Client" vs. Envoy "Mobile", that can enforce the various constraints for the mobile vs. non-mobile use case. There's already an ifdef guard for __APPLE__ guarding this code, but I suppose that would still execute on MacOS and other non-iOS Apple devices.

Also, ideally, EngineBuilder::build() would return StatusOr<EngineSharedPtr> instead of just EngineSharedPtr. That way, we could return a status error if the config is in a logically inconsistent state. But that would be a separate change.

For now, I'm OK with keeping this check as long as we write clear code comments explaining why we are also checking for !use_worker_thread_

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I moved the enforcement to both enableWorkerThread() and respectSystemProxySetings() so that the former takes precedence. Likewise for platform cert validation. PTAL.

Comment thread mobile/library/cc/engine_builder.h Outdated
EngineBuilder& enableBrotliDecompression(bool brotli_decompression_on);
EngineBuilder& enableSocketTagging(bool socket_tagging_on);
EngineBuilder& enableHttp3(bool http3_on);
EngineBuilder& setUseWorkerThread(bool use_worker_thread);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How about enableStandaloneWorkerThread? We should also add comments to clarify what this method does i.e. what a separate worker/network thread means

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

worker_started_notification.WaitForNotification();
ENVOY_LOG_MISC(info, "Worker thread has been started");

worker_->httpClient(); // Verify if it's null right after startup
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what does this comment mean here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

httpClient() ASSERT on client_ to be not null.

Comment thread mobile/library/common/internal_engine.cc
Comment thread mobile/.bazelrc
Comment thread mobile/library/common/internal_engine.cc
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
…ker thread

Signed-off-by: Dan Zhang <danzh@google.com>
abeyad
abeyad previously approved these changes Apr 16, 2026
Copy link
Copy Markdown
Contributor

@abeyad abeyad left a comment

Choose a reason for hiding this comment

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

thanks @danzh2010 !

Copy link
Copy Markdown
Contributor

@abeyad abeyad left a comment

Choose a reason for hiding this comment

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

@markdroth friendly ping on the API review, thanks!

Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants