Deployment
Production Server
use neutron::Neutron;
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let app = Neutron::new()
.router(router)
.shutdown_timeout(Duration::from_secs(30))
.on_shutdown(|| async { /* flush metrics, close connections */ })
.max_connections(10_000)
.workers(std::thread::available_parallelism()?.get())
.tcp_nodelay(true)
.tcp_keepalive(Some(Duration::from_secs(60)))
.listen("0.0.0.0:8080".parse()?)
.await?;
Ok(())
}
Graceful Shutdown
Neutron handles SIGINT and SIGTERM automatically:
- Stop accepting new connections
- Run pre-shutdown hooks in order
- Drain active connections (up to
shutdown_timeout) - Exit cleanly
Custom Shutdown Signal
let (tx, rx) = tokio::sync::oneshot::channel();
Neutron::new()
.router(router)
.shutdown_signal(async move { rx.await.ok(); })
.serve(8080)
.await?;
// Later: tx.send(()) triggers shutdown
Health Checks
Two built-in endpoints:
| Endpoint | Purpose | Response |
|----------|---------|----------|
| GET /healthz | Liveness probe | Always 200 OK |
| GET /readyz | Readiness probe | Runs all registered checks |
Register Checks
use neutron::health::HealthCheck;
let health = HealthCheck::new()
.check("database", || async {
pool.execute("SELECT 1").await.map(|_| ())
})
.check("redis", || async {
redis.ping().await
})
.timeout(Duration::from_secs(5));
let app = Neutron::new()
.router(router)
.health(health);
Response Format
{
"status": "healthy",
"checks": {
"database": { "status": "pass", "duration_ms": 2 },
"redis": { "status": "pass", "duration_ms": 1 }
}
}
If any check fails, status is "unhealthy" and HTTP status is 503.
HTTP/2 Configuration
use neutron::Http2Config;
Neutron::new()
.router(router)
.http2(Http2Config {
initial_stream_window_size: 2 * 1024 * 1024,
initial_connection_window_size: 4 * 1024 * 1024,
max_concurrent_streams: 200,
adaptive_window: true,
keep_alive_interval: Some(Duration::from_secs(20)),
..Default::default()
})
.serve(8080)
.await?;
Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| HOST | 127.0.0.1 | Bind address |
| PORT | 3000 | Listen port |
| DATABASE_URL | — | Nucleus/PostgreSQL connection string |
| LOG_LEVEL | info | Tracing filter (trace, debug, info, warn, error) |
| LOG_FORMAT | json | Log format (json or pretty) |
Docker
# Build stage
FROM rust:1.77-slim AS builder
WORKDIR /app
COPY . .
RUN cargo build --release --bin myapp
# Runtime stage
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/myapp /usr/local/bin/
EXPOSE 8080
ENV HOST=0.0.0.0 PORT=8080
CMD ["myapp"]
Docker Compose
services:
app:
build: .
ports:
- "8080:8080"
environment:
DATABASE_URL: postgres://nucleus:5432/mydb
LOG_LEVEL: info
depends_on:
nucleus:
condition: service_healthy
nucleus:
image: ghcr.io/neutron-build/nucleus:latest
ports:
- "5432:5432"
volumes:
- nucleus_data:/var/lib/nucleus
healthcheck:
test: ["CMD", "pg_isready", "-h", "localhost"]
interval: 5s
timeout: 5s
retries: 5
volumes:
nucleus_data:
systemd
[Unit]
Description=My Neutron App
After=network.target
[Service]
Type=simple
User=myapp
ExecStart=/usr/local/bin/myapp
Environment=HOST=0.0.0.0
Environment=PORT=8080
Environment=DATABASE_URL=postgres://localhost:5432/mydb
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
[Install]
WantedBy=multi-user.target
Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
template:
spec:
containers:
- name: myapp
image: myapp:latest
ports:
- containerPort: 8080
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-credentials
key: url
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /readyz
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"