Skip to content

Commit e303a27

Browse files
committed
Add support for virtual-pool? and connector threads configuration
1 parent 6cc7ad8 commit e303a27

File tree

3 files changed

+113
-30
lines changed

3 files changed

+113
-30
lines changed

.github/workflows/test.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ name: Tests
22
on: [push, pull_request]
33
jobs:
44
test:
5+
strategy:
6+
matrix:
7+
java_version: [17, 19, 21, 24]
58
runs-on: ubuntu-latest
69
steps:
710
- name: Checkout
@@ -11,7 +14,7 @@ jobs:
1114
uses: actions/setup-java@v3
1215
with:
1316
distribution: 'zulu'
14-
java-version: '17'
17+
java-version: ${{matrix.java_version}}
1518

1619
- name: Install clojure tools
1720
uses: DeLaGuardo/setup-clojure@10.1
@@ -46,4 +49,6 @@ jobs:
4649
working-directory: ./ring-jakarta-servlet
4750

4851
- name: Run tests
52+
env:
53+
_JAVA_OPTIONS: ${{ matrix.java_version == 19 && '--enable-preview' || '' }}
4954
run: lein sub test-all

ring-jetty-adapter/src/ring/adapter/jetty.clj

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
[org.eclipse.jetty.unixdomain.server UnixDomainServerConnector]
2020
[org.eclipse.jetty.ee9.servlet ServletContextHandler ServletHandler]
2121
[org.eclipse.jetty.util BlockingArrayQueue]
22-
[org.eclipse.jetty.util.thread ThreadPool QueuedThreadPool]
22+
[org.eclipse.jetty.util.thread ThreadPool QueuedThreadPool VirtualThreadPool]
2323
[org.eclipse.jetty.util.ssl SslContextFactory$Server KeyStoreScanner]
2424
[org.eclipse.jetty.ee9.nested Request]
2525
[org.eclipse.jetty.ee9.websocket.server
@@ -168,14 +168,38 @@
168168
(.setAllowNullPathInfo true)
169169
(JettyWebSocketServletContainerInitializer/configure nil)))
170170

171-
(defn- server-connector ^ServerConnector [^Server server & factories]
172-
(ServerConnector. server #^"[Lorg.eclipse.jetty.server.ConnectionFactory;"
173-
(into-array ConnectionFactory factories)))
171+
(defn- get-connector-thread-options [options]
172+
(let [acceptors (options :acceptor-threads
173+
(when (:virtual-pool? options)
174+
1))
175+
selectors (options :selector-threads
176+
(when acceptors
177+
(-> (Runtime/getRuntime) (.availableProcessors))))]
178+
{:acceptors acceptors
179+
:selectors selectors}))
180+
181+
(defn- server-connector ^ServerConnector [^Server server factories options]
182+
(let [{:keys [acceptors
183+
selectors]} (get-connector-thread-options options)]
184+
(if (and acceptors selectors)
185+
(ServerConnector. server (int acceptors) (int selectors)
186+
^{:tag "[Lorg.eclipse.jetty.server.ConnectionFactory;"}
187+
(into-array ConnectionFactory factories))
188+
(ServerConnector. server
189+
^{:tag "[Lorg.eclipse.jetty.server.ConnectionFactory;"}
190+
(into-array ConnectionFactory factories)))))
174191

175192
(defn- unix-domain-server-connector ^UnixDomainServerConnector
176-
[^Server server & factories]
177-
(UnixDomainServerConnector. server #^"[Lorg.eclipse.jetty.server.ConnectionFactory;"
178-
(into-array ConnectionFactory factories)))
193+
[^Server server factories options]
194+
(let [{:keys [acceptors
195+
selectors]} (get-connector-thread-options options)]
196+
(if (and acceptors selectors)
197+
(UnixDomainServerConnector. server (int acceptors) (int selectors)
198+
^{:tag "[Lorg.eclipse.jetty.server.ConnectionFactory;"}
199+
(into-array ConnectionFactory factories))
200+
(UnixDomainServerConnector. server
201+
^{:tag "[Lorg.eclipse.jetty.server.ConnectionFactory;"}
202+
(into-array ConnectionFactory factories)))))
179203

180204
(defn- http-config ^HttpConfiguration [options]
181205
(doto (HttpConfiguration.)
@@ -187,7 +211,7 @@
187211

188212
(defn- http-connector ^ServerConnector [server options]
189213
(let [http-factory (HttpConnectionFactory. (http-config options))]
190-
(doto (server-connector server http-factory)
214+
(doto (server-connector server [http-factory] options)
191215
(.setPort (options :port 80))
192216
(.setHost (options :host))
193217
(.setIdleTimeout (options :max-idle-time 200000)))))
@@ -239,7 +263,7 @@
239263
(when-let [scan-interval (options :keystore-scan-interval)]
240264
(.addBean server (doto (KeyStoreScanner. ssl-context)
241265
(.setScanInterval scan-interval))))
242-
(doto (server-connector server ssl-factory http-factory)
266+
(doto (server-connector server [ssl-factory http-factory] options)
243267
(.setPort ssl-port)
244268
(.setHost (options :host))
245269
(.setIdleTimeout (options :max-idle-time 200000)))))
@@ -248,7 +272,7 @@
248272
(let [http-factory (HttpConnectionFactory. (http-config options))
249273
socket (io/file (options :unix-socket))]
250274
(.deleteOnExit socket)
251-
(doto (unix-domain-server-connector server http-factory)
275+
(doto (unix-domain-server-connector server [http-factory] options)
252276
(.setUnixDomainPath (.toPath socket))
253277
(.setIdleTimeout (options :max-idle-time 200000)))))
254278

@@ -269,8 +293,16 @@
269293
(.setDaemon pool true))
270294
pool))
271295

296+
(defn- create-virtual-threadpool [options]
297+
(let [max-threads (options :max-threads 50)
298+
pool (VirtualThreadPool. max-threads)]
299+
pool))
300+
272301
(defn- create-server ^Server [options]
273-
(let [pool (or (:thread-pool options) (create-threadpool options))
302+
(let [pool (or (:thread-pool options)
303+
(when (:virtual-pool? options false)
304+
(create-virtual-threadpool options))
305+
(create-threadpool options))
274306
server (Server. ^ThreadPool pool)]
275307
(when (:http? options true)
276308
(.addConnector server (http-connector server options)))
@@ -317,8 +349,13 @@
317349
:keystore-scan-interval - if not nil, the interval in seconds to scan for an
318350
updated keystore
319351
:thread-pool - custom thread pool instance for Jetty to use
352+
:virtual-pool? - use a VirtualThreadPool (requires Java 19+)
320353
:truststore - a truststore to use for SSL connections
321354
:trust-password - the password to the truststore
355+
:acceptor-threads - the number of acceptor threads to use
356+
(default 1 if using virtual-pool?, otherwise not set)
357+
:selector-threads - the number of selector threads to use
358+
(default to available processors if using virtual-pool?, otherwise not set)
322359
:max-threads - the maximum number of threads to use (default 50)
323360
:min-threads - the minimum number of threads to use (default 8)
324361
:max-queued-requests - the maximum number of requests to be queued

ring-jetty-adapter/test/ring/adapter/test/jetty.clj

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
(:import [java.io File]
1212
[java.nio ByteBuffer]
1313
[java.nio.file Paths]
14-
[org.eclipse.jetty.util.thread QueuedThreadPool]
14+
[org.eclipse.jetty.util.thread QueuedThreadPool VirtualThreadPool]
1515
[org.eclipse.jetty.server Server Request SslConnectionFactory]
1616
[org.eclipse.jetty.server.handler AbstractHandler]
1717
[org.eclipse.jetty.io ClientConnector Transport$TCPUnix]
@@ -103,6 +103,11 @@
103103
:join? false
104104
:sni-host-check? false})
105105

106+
(def java-version
107+
(->> (System/getProperty "java.version")
108+
(re-find #"\A\d+")
109+
(Integer/parseInt)))
110+
106111
(deftest test-run-jetty
107112
(testing "HTTP server"
108113
(with-server hello-world {:port test-port}
@@ -112,23 +117,29 @@
112117
"text/plain"))
113118
(is (= (:body response) "Hello World")))))
114119

115-
(let [java-version (->> (System/getProperty "java.version")
116-
(re-find #"\A\d+")
117-
(Integer/parseInt))]
118-
(when (>= java-version 16)
119-
(testing "UNIX Socket server"
120-
(with-server hello-world {:http? false
121-
:unix-socket test-unix-domain-socket}
122-
(let [path (Paths/get test-unix-domain-socket (make-array String 0))
123-
transport (HttpClientTransportOverHTTP. (ClientConnector.))
124-
client (doto (HttpClient. transport) (.start))
125-
response (-> client
126-
(.newRequest "http://localhost")
127-
(.transport (Transport$TCPUnix. path))
128-
(.send))]
129-
(is (= (.getStatus response) 200))
130-
(is (.getMediaType response) "text/plain")
131-
(is (= (.getContentAsString response) "Hello World")))))))
120+
(when (>= java-version 16)
121+
(testing "UNIX Socket server"
122+
(with-server hello-world {:http? false
123+
:unix-socket test-unix-domain-socket}
124+
(let [path (Paths/get test-unix-domain-socket (make-array String 0))
125+
transport (HttpClientTransportOverHTTP. (ClientConnector.))
126+
client (doto (HttpClient. transport) (.start))
127+
response (-> client
128+
(.newRequest "http://localhost")
129+
(.transport (Transport$TCPUnix. path))
130+
(.send))]
131+
(is (= (.getStatus response) 200))
132+
(is (.getMediaType response) "text/plain")
133+
(is (= (.getContentAsString response) "Hello World"))))
134+
135+
(when (>= java-version 19)
136+
(testing "with custom connector options"
137+
(let [server (run-jetty hello-world {:http? false
138+
:unix-socket test-unix-domain-socket
139+
:join? false
140+
:acceptor-threads 2})]
141+
(is (= 2 (-> server (.getConnectors) first (.getAcceptors))))
142+
(.stop server))))))
132143

133144
(testing "HTTPS server"
134145
(with-server hello-world {:port test-port
@@ -331,6 +342,36 @@
331342
(is (= 1000 (. thread-pool getIdleTimeout)))
332343
(.stop server)))
333344

345+
(when (>= java-version 19)
346+
(testing "using default connector options with virtual-pool?"
347+
(let [server (run-jetty hello-world {:port test-port
348+
:join? false
349+
:virtual-pool? true})]
350+
(is (instance? VirtualThreadPool (.getThreadPool server)))
351+
(is (= 1 (-> server (.getConnectors) first (.getAcceptors))))
352+
(is (= (-> (Runtime/getRuntime) (.availableProcessors))
353+
(-> server (.getConnectors) first (.getSelectorManager) (.getSelectorCount))))
354+
(.stop server))))
355+
356+
(testing "using missing connector options with default pool"
357+
(let [server (run-jetty hello-world {:port test-port
358+
:join? false})]
359+
(is (instance? QueuedThreadPool (.getThreadPool server)))
360+
(is (= 1 (-> server (.getConnectors) first (.getAcceptors))))
361+
(is (> (-> (Runtime/getRuntime) (.availableProcessors))
362+
(-> server (.getConnectors) first (.getSelectorManager) (.getSelectorCount))))
363+
(.stop server)))
364+
365+
(testing "using custom connector options"
366+
(let [server (run-jetty hello-world {:port test-port
367+
:join? false
368+
:acceptor-threads 2
369+
:selector-threads 8})]
370+
(is (= 2 (-> server (.getConnectors) first (.getAcceptors))))
371+
(is (= 8
372+
(-> server (.getConnectors) first (.getSelectorManager) (.getSelectorCount))))
373+
(.stop server)))
374+
334375
(testing "providing custom thread-pool"
335376
(let [pool (QueuedThreadPool.)
336377
server (run-jetty hello-world {:port test-port

0 commit comments

Comments
 (0)