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:

  1. Stop accepting new connections
  2. Run pre-shutdown hooks in order
  3. Drain active connections (up to shutdown_timeout)
  4. 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"