Paul Rütter created FELIX-6859:
----------------------------------
Summary: Jetty's preferred virtual threads setup cannot be
configured
Key: FELIX-6859
URL: https://issues.apache.org/jira/browse/FELIX-6859
Project: Felix
Issue Type: New Feature
Components: HTTP Service
Reporter: Paul Rütter
h2. Current behaviour
{{JettyService.createServer()}} in the jetty12 bundle builds one of four thread
pools,
selected by {{org.apache.felix.http.jetty.virtualthreads.enable}} and
{{org.apache.felix.http.jetty.threadpool.max}}:
|| virtualthreads.enable || threadpool.max || Thread pool ||
| false | unset (-1) | Jetty's default {{QueuedThreadPool}}, 200 platform
threads |
| false | set | {{QueuedThreadPool}} with {{<max>}} platform threads |
| true | unset (-1) | {{QueuedThreadPool}} whose virtual threads executor is
{{Executors.newVirtualThreadPerTaskExecutor()}} - unbounded |
| true | set | standalone {{VirtualThreadPool}} with
{{setMaxConcurrentTasks(<max>)}} |
h2. What is missing
The [Jetty 12 programming
guide|https://jetty.org/docs/jetty/12/programming-guide/arch/threads.html#thread-pool-virtual-threads]
documents a fifth shape as the preferred one: a {{QueuedThreadPool}} whose
virtual
threads executor is a *bounded* {{VirtualThreadPool}}.
{code:java}
QueuedThreadPool threadPool = new QueuedThreadPool();
VirtualThreadPool virtualThreadPool = new VirtualThreadPool();
virtualThreadPool.setMaxConcurrentTasks(maxConcurrentTasks);
threadPool.setVirtualThreadsExecutor(virtualThreadPool);
Server server = new Server(threadPool);
{code}
There is no Felix HTTP configuration that produces this. The two virtual thread
options currently available are the extremes:
* {{threadpool.max}} unset gives an unbounded number of concurrent virtual
thread
tasks, which Jetty warns can exhaust memory during a load spike.
* {{threadpool.max}} set gives a standalone {{VirtualThreadPool}}, which is not
a
{{ThreadPool.SizedThreadPool}}. Jetty therefore sizes the selectors with
{{max(1, cpus / 2)}} instead of {{max(1, min(cpus / 2, maxThreads / 16))}},
and the
pool creates only virtual threads.
A deployment that wants platform threads for the acceptors and the selectors
*and* a
bound on concurrent request tasks cannot express that today.
h2. Proposal
Add a property for the bound on concurrent virtual thread tasks that is
separate from
the platform thread pool size, for example
{{org.apache.felix.http.jetty.virtualthreads.maxConcurrentTasks}}.
When {{virtualthreads.enable}} is true and that property is set, build a
{{QueuedThreadPool}} (sized by {{threadpool.max}} as usual) whose virtual
threads
executor is a {{VirtualThreadPool}} with {{setMaxConcurrentTasks}} set to that
value.
This also disentangles {{threadpool.max}}, which currently means two different
things
depending on {{virtualthreads.enable}}: the platform thread count of a
{{QueuedThreadPool}} in one case, the concurrent task limit of a
{{VirtualThreadPool}}
in the other.
h2. Open questions
* Lifecycle. {{QueuedThreadPool.setVirtualThreadsExecutor(Executor)}} only
stores the
reference; it does not add the argument as a managed bean.
{{VirtualThreadPool}} is a
{{ContainerLifeCycle}} and needs to be started and stopped, so it likely has
to be
added as a bean to the server or to the thread pool explicitly.
* Backwards compatibility. Should the existing {{virtualthreads.enable}} +
{{threadpool.max}} combination keep producing the standalone
{{VirtualThreadPool}}, or
should the preferred shape become the default for that combination? The first
is
safer; the second matches the Jetty recommendation.
* jetty11 bundle. It has no {{virtualthreads.enable}} at all, so this is
jetty12 only.
h2. Documentation
The "Thread pool and virtual threads" section of {{http/README.md}} spells out
the four
existing combinations and notes this gap. It needs a row for the new
combination, and
the note should be removed once this is implemented.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)