This runbook documents operational procedures for the NioFlow reference service (task-planner-app) and the underlying framework runtime.
flowchart LR
Client[Client / API Consumer] --> App[NioFlow Service]
App --> DB[(PostgreSQL)]
App --> Metrics[/metrics endpoint/]
App --> Health[/_health endpoint/]
App --> Ready[/_ready endpoint/]
sequenceDiagram
participant C as Client
participant S as Selector Thread
participant W as Worker Pool
participant R as Router+Middleware
participant H as Handler
participant D as DB Executor
C->>S: HTTP request
S->>W: dispatch socket
W->>R: parse + resolve route
R->>H: invoke controller
H->>D: async JDBC task
D-->>H: result
H-->>W: response
W-->>C: HTTP response
- Java 17+
- Maven 3.9+
- PostgreSQL 15+ (only when DB mode is enabled)
JWT_SECRET(or-Dnioflow.jwtSecret=...)- Must be at least 32 characters.
- Service startup should fail fast if missing/weak.
NIOFLOW_ENABLE_DB=trueDB_PASS
JDBC_URL(defaultjdbc:postgresql://localhost:5432/nioflow)DB_USER(defaultpostgres)NIOFLOW_THREADS(default10)NIOFLOW_QUEUE_CAPACITY(default100)NIOFLOW_SOCKET_TIMEOUT_MS(default15000)NIOFLOW_CORS_ORIGIN(defaulthttp://localhost:3000in app bootstrap)NIOFLOW_STATIC_DIR(auto-resolved when unset)NIOFLOW_EXPOSE_ERROR_DETAILS(defaultfalse; keep false in production)
NIOFLOW_TLS_ENABLED=trueNIOFLOW_TLS_KEYSTORE_PATH=/path/to/keystore.jksNIOFLOW_TLS_KEYSTORE_PASSWORD=<keystore-password>NIOFLOW_TLS_PORT=8443(optional)
export JWT_SECRET="replace-with-long-random-secret-32-plus-chars"
export NIOFLOW_ENABLE_DB=true
export DB_PASS="replace-with-strong-password"
export JDBC_URL="jdbc:postgresql://db-host:5432/nioflow"
export DB_USER="nioflow_app"
export NIOFLOW_THREADS=20
export NIOFLOW_QUEUE_CAPACITY=200
export NIOFLOW_CORS_ORIGIN="https://yourdomain.com"./mvnw clean testWindows PowerShell alternative:
.\mvn.ps1 clean test./mvnw package -DskipTests -pl task-planner-app -am./mvnw exec:java -pl task-planner-app \
-Dexec.mainClass=io.github.jhanvi857.taskplanner.DemoApplication \
-Dnioflow.jwtSecret=replace-with-long-secretjava \
-Dnioflow.jwtSecret=replace-with-long-secret \
-Dnioflow.threads=20 \
-Dnioflow.queueCapacity=200 \
-jar task-planner-app/target/task-planner-app-1.0-SNAPSHOT-jar-with-dependencies.jarRun these checks after startup and after each deploy:
curl -i http://localhost:8080/_health
curl -i http://localhost:8080/_ready
curl -i http://localhost:8080/metrics
curl -i http://localhost:8080/api/tasks/Expected results:
/_health->200with JSON status payload./_ready->200when dependencies are ready,503when DB mode is on but DB is unavailable./metrics->200with metrics text content./api/tasks/without auth ->401 Unauthorized.
Optional auth check:
curl -i http://localhost:8080/api/secure/ \
-H "Authorization: Bearer <valid-token>"- Path:
/_health - Purpose: quick liveness check + JVM memory snapshot.
Example response:
{
"status": "UP",
"memory_used_mb": 42
}- Path:
/_ready - Purpose: dependency-aware readiness check for deploy cutovers and load balancer probes.
- Path:
/metrics - Purpose: scrape-friendly counters/histogram text for monitoring systems.
- Output target: STDOUT.
- Format:
timestamp [thread] level logger - message.
Common log signals to watch:
Server busy! Rejecting connection.Malformed request from clientUnhandled ExceptionTLS Handshake failure
- Protected route groups:
/api/tasks/*/api/secure/*
- Middleware:
AuthMiddleware. - Missing or invalid bearer token must return
401.
- Never commit secrets to source control.
- Rotate
JWT_SECRETand DB credentials periodically. - Use platform secret stores for production.
Choose one:
- Terminate TLS at reverse proxy (Nginx/Caddy/ALB) and run app on HTTP internally.
- Use native framework TLS via
listenSecure(...)and keystore management.
- Rate limiting enabled globally (
100requests /10seconds by default). - Bounded thread queue and worker pool reduce memory amplification under load.
- Pull target commit/tag.
- Run
./mvnw clean test. - Run
./mvnw package -DskipTests -pl task-planner-app -am. - Export required env vars (
JWT_SECRET, DB settings). - Start JAR process.
- Perform health verification checklist.
- Switch traffic.
Run old and new versions in parallel behind a proxy/load balancer, then cut over only after the new version passes health and auth checks.
Use the bundled k6 script to validate worker/queue sizing before production rollout:
# Linux/macOS
BASE_URL=http://localhost:8080 ./scripts/load-test.sh
# Windows PowerShell
$env:BASE_URL="http://localhost:8080"
./scripts/load-test.ps1- Check logs for
Unhandled Exceptionand stack traces. - Verify DB connectivity and credentials.
- Check recent deploy diff.
- Roll back to previous known-good artifact if error rate stays high.
Symptoms indicate queue saturation and worker exhaustion.
- Check concurrency and request rate patterns.
- Increase
NIOFLOW_THREADSandNIOFLOW_QUEUE_CAPACITYcarefully. - Confirm DB latency is not the bottleneck.
- Apply rate limiting / upstream throttling if traffic is abusive.
- Verify
JWT_SECRETmatches the issuer key. - Validate token expiry and signature algorithm.
- Confirm request carries
Authorization: Bearer <token>.
If release health checks fail:
- Stop current process.
- Start previous artifact version with prior config.
- Verify
/_healthand auth behavior. - Keep failed artifact and logs for postmortem analysis.
The CI workflow includes:
- Build and unit tests.
- Integration tests.
- Container build validation.
- Blocking dependency vulnerability scanning (OWASP Dependency Check).
Before promoting to production, ensure the target commit has green CI status.
- Review error-rate trends and saturation logs.
- Inspect dependency scan report.
- Validate backup and restore readiness for DB.
- Rotate secrets where policy requires.
- Re-run load tests with production-like traffic profile.
- Recalibrate worker/queue/DB pool sizing.
# Build + test
./mvnw clean test
# Package app only
./mvnw package -DskipTests -pl task-planner-app -am
# Run app
java -Dnioflow.jwtSecret=<secret> -jar task-planner-app/target/task-planner-app-1.0-SNAPSHOT-jar-with-dependencies.jar
# Health
curl -i http://localhost:8080/_health
# Metrics
curl -i http://localhost:8080/metrics