https://github.com/macielti/service
Service Component is a Pedestal service Integrant component
https://github.com/macielti/service
clojure integrant pedestal
Last synced: about 1 month ago
JSON representation
Service Component is a Pedestal service Integrant component
- Host: GitHub
- URL: https://github.com/macielti/service
- Owner: macielti
- License: other
- Created: 2024-11-09T00:47:29.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2026-05-01T03:30:28.000Z (about 1 month ago)
- Last Synced: 2026-05-01T03:41:48.614Z (about 1 month ago)
- Topics: clojure, integrant, pedestal
- Language: Clojure
- Homepage: https://github.com/macielti/service-component
- Size: 93.8 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
[](https://clojars.org/net.clojars.macielti/service-component)

# Service
Service is a Pedestal service Integrant component.
If you will be using this library in a project intended to be compiled using GraalVM, you should add the following
dependencies to your project:
``` clojure
[net.clojars.macielti/service "x.y.z"]
[io.pedestal/pedestal.service "0.8.1"]
[io.pedestal/pedestal.jetty "0.8.1"]
[io.pedestal/pedestal.error "0.8.1"]
```
## Configuration
The service component accepts configuration through the `:service` key in your config map. The following options are available:
| Key | Type | Required | Default | Description |
|------------------------|---------------------|----------|-------------------|----------------------------------------------------------------------------------------------------------------|
| `:host` | String | Yes | — | The host address to bind the server to (e.g., `"0.0.0.0"`). |
| `:port` | Integer | Yes | — | The port number to listen on (e.g., `8080`). |
| `:idle-timeout-ms` | Integer | No | `30000` | Jetty idle timeout in milliseconds. Connections idle beyond this duration are closed. |
| `:min-threads` | Integer | No | `8` | Minimum number of threads kept alive in the Jetty thread pool. |
| `:max-threads` | Integer | No | `50` | Maximum number of concurrent threads. Acts as a concurrency cap for both platform and virtual thread modes. |
| `:max-queue-size` | Integer | No | `200` | Maximum number of requests that can queue while all threads are busy (platform threads only). Requests beyond this limit are rejected with HTTP 503. |
| `:use-virtual-threads` | Boolean | No | `true` | When `true` and running on Java 21+, uses Jetty's `VirtualThreadPool` instead of `QueuedThreadPool`. Falls back to platform threads automatically on Java < 21. |
### Thread pool behaviour
The component selects the thread pool implementation at startup based on `:use-virtual-threads` and the detected JVM version:
**Virtual threads (Java 21+, default)**
Uses Jetty's `VirtualThreadPool`. Each request runs in its own virtual thread, which is cheap to create (~few KB) and automatically yields during blocking I/O, allowing thousands of concurrent requests without stacking platform threads. Concurrency is bounded by `:max-threads` via a semaphore. `:min-threads` and `:max-queue-size` are ignored in this mode.
**Platform threads (Java < 21, or `:use-virtual-threads false`)**
Uses Jetty's `QueuedThreadPool` backed by a `BlockingArrayQueue` of size `:max-queue-size`. Requests are served by a pool of `:min-threads` to `:max-threads` platform threads. When all threads are busy and the queue is full, new requests are rejected immediately with **HTTP 503**, providing explicit backpressure instead of silently growing memory until OOM.
### Example
```clojure
{:service {:host "0.0.0.0"
:port 8080
:idle-timeout-ms 60000
:min-threads 8
:max-threads 200
:max-queue-size 500
:use-virtual-threads true}}
```
### Recommended values by workload
| Scenario | `:min-threads` | `:max-threads` | `:max-queue-size` |
|-----------------------------|----------------|----------------|-------------------|
| IO-bound (DB, HTTP calls) | `8` | `100`–`200` | `500` |
| CPU-bound | `4` | `nCPU × 2` | `50` |
| Small pods / low memory | `4` | `20` | `100` |
| Java 21+ (virtual threads) | — | `500`+ | — |
> **Note:** If `:idle-timeout-ms` is not provided, a default of **30 seconds** (`30000` ms) is applied to prevent stalled connections from tying up server resources.
## Interceptors
CORS and other default request interceptors must be configured **in your consuming application**, not at the component level.
The service component provides two built-in interceptors:
- `error-handler-interceptor` — handles exception-to-response conversion.
- `components-interceptor` — injects the Integrant components map into the request context.
To add CORS, authentication, rate limiting, or other cross-cutting concerns, use one of these approaches in your application:
**Option 1: Per-route interceptors**
Define interceptors on individual routes in your route definitions:
```clojure
["/api/resource"
{:get {:handler my-handler
:interceptors [cors-interceptor auth-interceptor]}}]
```
**Option 2: Connector-level default interceptors**
Use `io.pedestal.connector/with-default-interceptors` in your route setup to apply interceptors to all routes:
```clojure
(io.pedestal.connector/with-default-interceptors connector :allowed-origins cors-origins)
```
## License
Copyright © 2024 Bruno do Nascimento Maciel
This program and the accompanying materials are made available under the
terms of the Eclipse Public License 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0.
This Source Code may also be made available under the following Secondary
Licenses when the conditions for such availability set forth in the Eclipse
Public License, v. 2.0 are satisfied: GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or (at your
option) any later version, with the GNU Classpath Exception which is available
at https://www.gnu.org/software/classpath/license.html.