Executor Model

KissServer separates network I/O from normal application handler execution.

Selector And Event Loop

The NIO engine uses a selector thread for network work:

The selector thread should stay fast. Blocking work belongs on an executor through the normal route path.

Normal Handlers Use ExecutorService

HandlerExecutionMode.WORKER is the default. In this mode normal handlers run on the configured ExecutorService:

ServerConfig config = ServerConfig.builder()
        .handlerExecutionMode(HandlerExecutionMode.WORKER)
        .build();

Use this for normal application behavior, especially handlers that might block or take measurable CPU time.

Fast Path Can Avoid The Executor

Exact fixed GET routes registered with fastGet can be served directly by the NIO engine:

server.fastGet("/health", FastResponses.text("OK"));

This is appropriate only for fixed responses. Do not hide slow work in the fast path.

Java 17 Default Executor

KissServer compiles on Java 17. Main source does not directly call JDK 21-only APIs.

If no executor is provided, KissServer creates an internal default executor. That executor is owned by the server and is shut down when the server stops.

User-Provided Executor

Applications may pass an executor:

ExecutorService executor = Executors.newFixedThreadPool(
        Math.max(4, Runtime.getRuntime().availableProcessors())
);

ServerConfig config = ServerConfig.builder()
        .port(8080)
        .executor(executor)
        .build();

If the application provides the executor, KissServer does not shut it down automatically. The application owns its lifecycle.

Ownership Rules

JDK 21 Virtual Threads From Application Code Only

JDK 21+ applications may pass:

ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

ServerConfig config = ServerConfig.builder()
        .executor(executor)
        .build();

This is optional application code. It must not become required library usage and must not be called directly from kiss-server main source.

Benchmark reports must label this profile as kiss-server on JDK 21 with virtual-thread executor.

Direct Mode

DIRECT runs normal handlers on the selector thread:

ServerConfig config = ServerConfig.builder()
        .handlerExecutionMode(HandlerExecutionMode.DIRECT)
        .build();

Use DIRECT only for controlled, non-blocking, fast handlers. Do not use it for database calls, file I/O, network calls, sleeps, synchronous logging, or slow CPU work.

Android Implications

Android compatibility is a design goal pending validation. Keep application examples on Java 17 APIs by default. Do not require virtual threads for Android. Android lifecycle, background execution, battery optimization, network changes, and port accessibility must be handled by the application.

Blocking Handler Implications

Blocking handlers can exhaust executor threads or increase latency. For blocking-heavy apps:

Workload Java 17 choice Notes
CPU-small handlers fixed pool near CPU count predictable resource use
Mixed blocking handlers cached pool or tuned fixed pool measure queueing and memory
Many blocking calls on JDK 21 virtual-thread executor optional application code
Fixed static health/version fast path no normal executor work

Always benchmark with the same executor settings you plan to deploy.