99package dev .restate .sdk .http .vertx ;
1010
1111import dev .restate .sdk .endpoint .Endpoint ;
12- import io .vertx .core .Future ;
12+ import io .vertx .core .AbstractVerticle ;
13+ import io .vertx .core .DeploymentOptions ;
14+ import io .vertx .core .Promise ;
1315import io .vertx .core .Vertx ;
14- import io .vertx .core .http . Http2Settings ;
16+ import io .vertx .core .VertxOptions ;
1517import io .vertx .core .http .HttpServer ;
1618import io .vertx .core .http .HttpServerOptions ;
1719import java .util .Optional ;
1820import java .util .concurrent .CompletionException ;
21+ import java .util .concurrent .atomic .AtomicInteger ;
1922import org .apache .logging .log4j .LogManager ;
2023import org .apache .logging .log4j .Logger ;
2124
@@ -42,9 +45,8 @@ public class RestateHttpServer {
4245
4346 private static final int DEFAULT_PORT =
4447 Optional .ofNullable (System .getenv ("PORT" )).map (Integer ::parseInt ).orElse (9080 );
45- private static final HttpServerOptions DEFAULT_OPTIONS =
46- new HttpServerOptions ()
47- .setInitialSettings (new Http2Settings ().setMaxConcurrentStreams (Integer .MAX_VALUE ));
48+ private static final HttpServerOptions DEFAULT_HTTP_SERVER_OPTIONS = new HttpServerOptions ();
49+ private static final int DEFAULT_EVENT_LOOPS = VertxOptions .DEFAULT_EVENT_LOOP_POOL_SIZE ;
4850
4951 /**
5052 * Start serving the provided {@code endpoint} on the port specified by the environment variable
@@ -54,10 +56,10 @@ public class RestateHttpServer {
5456 * non-blocking variant, manually create the server with {@link #fromEndpoint(Endpoint)} and start
5557 * listening it.
5658 *
57- * @return The listening port
59+ * @return The listening port, use 0 for random port.
5860 */
5961 public static int listen (Endpoint endpoint ) {
60- return handleStart ( fromEndpoint ( endpoint ). listen (DEFAULT_PORT ) );
62+ return listen (endpoint , DEFAULT_PORT );
6163 }
6264
6365 /** Like {@link #listen(Endpoint)} */
@@ -72,10 +74,10 @@ public static int listen(Endpoint.Builder endpointBuilder) {
7274 * non-blocking variant, manually create the server with {@link #fromEndpoint(Endpoint)} and start
7375 * listening it.
7476 *
75- * @return The listening port
77+ * @return The listening port, use 0 for random port.
7678 */
7779 public static int listen (Endpoint endpoint , int port ) {
78- return handleStart ( fromEndpoint (endpoint ). listen ( port ) );
80+ return listen ( HttpEndpointRequestHandler . fromEndpoint (endpoint ), port );
7981 }
8082
8183 /** Like {@link #listen(Endpoint, int)} */
@@ -90,12 +92,12 @@ public static int listen(HttpEndpointRequestHandler requestHandler) {
9092
9193 /** Like {@link #listen(Endpoint, int)}, with an already built request handler */
9294 public static int listen (HttpEndpointRequestHandler requestHandler , int port ) {
93- return handleStart ( fromHandler ( requestHandler ). listen ( port ) );
95+ return listenBlocking ( requestHandler , port );
9496 }
9597
9698 /** Create a Vert.x {@link HttpServer} from the provided endpoint. */
9799 public static HttpServer fromEndpoint (Endpoint endpoint ) {
98- return fromEndpoint (endpoint , DEFAULT_OPTIONS );
100+ return fromEndpoint (endpoint , DEFAULT_HTTP_SERVER_OPTIONS );
99101 }
100102
101103 /** Like {@link #fromEndpoint(Endpoint)} */
@@ -119,7 +121,7 @@ public static HttpServer fromEndpoint(
119121
120122 /** Create a Vert.x {@link HttpServer} from the provided endpoint. */
121123 public static HttpServer fromEndpoint (Vertx vertx , Endpoint endpoint ) {
122- return fromEndpoint (vertx , endpoint , DEFAULT_OPTIONS );
124+ return fromEndpoint (vertx , endpoint , DEFAULT_HTTP_SERVER_OPTIONS );
123125 }
124126
125127 /** Like {@link #fromEndpoint(Vertx, Endpoint)} */
@@ -143,7 +145,7 @@ public static HttpServer fromEndpoint(
143145
144146 /** Create a Vert.x {@link HttpServer} from the provided {@link HttpEndpointRequestHandler}. */
145147 public static HttpServer fromHandler (HttpEndpointRequestHandler handler ) {
146- return fromHandler (handler , DEFAULT_OPTIONS );
148+ return fromHandler (handler , DEFAULT_HTTP_SERVER_OPTIONS );
147149 }
148150
149151 /**
@@ -157,7 +159,7 @@ public static HttpServer fromHandler(
157159
158160 /** Create a Vert.x {@link HttpServer} from the provided {@link HttpEndpointRequestHandler}. */
159161 public static HttpServer fromHandler (Vertx vertx , HttpEndpointRequestHandler handler ) {
160- return fromHandler (vertx , handler , DEFAULT_OPTIONS );
162+ return fromHandler (vertx , handler , DEFAULT_HTTP_SERVER_OPTIONS );
161163 }
162164
163165 /**
@@ -171,19 +173,74 @@ public static HttpServer fromHandler(
171173 return server ;
172174 }
173175
174- private static int handleStart (Future <HttpServer > fut ) {
176+ private static int listenBlocking (HttpEndpointRequestHandler handler , int port ) {
177+ String eventLoopsOverride =
178+ System .getProperty (
179+ "dev.restate.sdk.http.eventLoops" , System .getenv ("RESTATE_SDK_HTTP_EVENT_LOOPS" ));
180+ int instances =
181+ eventLoopsOverride != null ? Integer .parseInt (eventLoopsOverride ) : DEFAULT_EVENT_LOOPS ;
182+ Vertx vertx = Vertx .vertx (new VertxOptions ().setEventLoopPoolSize (instances ));
183+ // A negative port makes all the server instances share the same random port, whereas port 0
184+ // would make each instance bind a different random port.
185+ int listenPort = port == 0 ? -1 : port ;
186+ AtomicInteger actualPort = new AtomicInteger ();
175187 try {
176- HttpServer server = fut .toCompletionStage ().toCompletableFuture ().join ();
177- LOG .info ("Restate HTTP Endpoint server started on port {}" , server .actualPort ());
178- return server .actualPort ();
188+ vertx
189+ .deployVerticle (
190+ () ->
191+ new RestateServerVerticle (
192+ handler , DEFAULT_HTTP_SERVER_OPTIONS , listenPort , actualPort ),
193+ new DeploymentOptions ().setInstances (instances ))
194+ .toCompletionStage ()
195+ .toCompletableFuture ()
196+ .join ();
197+ LOG .info (
198+ "Restate HTTP Endpoint server started on port {} with {} event loop(s)" ,
199+ actualPort .get (),
200+ instances );
201+ return actualPort .get ();
179202 } catch (CompletionException e ) {
180203 LOG .error ("Restate HTTP Endpoint server start failed" , e .getCause ());
204+ vertx .close ();
181205 sneakyThrow (e .getCause ());
182206 // This is never reached
183207 return -1 ;
184208 }
185209 }
186210
211+ private static final class RestateServerVerticle extends AbstractVerticle {
212+
213+ private final HttpEndpointRequestHandler handler ;
214+ private final HttpServerOptions options ;
215+ private final int port ;
216+ private final AtomicInteger actualPort ;
217+
218+ private RestateServerVerticle (
219+ HttpEndpointRequestHandler handler ,
220+ HttpServerOptions options ,
221+ int port ,
222+ AtomicInteger actualPort ) {
223+ this .handler = handler ;
224+ this .options = options ;
225+ this .port = port ;
226+ this .actualPort = actualPort ;
227+ }
228+
229+ @ Override
230+ public void start (Promise <Void > startPromise ) {
231+ HttpServer server = vertx .createHttpServer (options );
232+ server .requestHandler (handler );
233+ server
234+ .listen (port )
235+ .onSuccess (
236+ s -> {
237+ actualPort .set (s .actualPort ());
238+ startPromise .complete ();
239+ })
240+ .onFailure (startPromise ::fail );
241+ }
242+ }
243+
187244 @ SuppressWarnings ("unchecked" )
188245 private static <E extends Throwable > void sneakyThrow (Throwable e ) throws E {
189246 throw (E ) e ;
0 commit comments