Chapter 25: Production Deployment, Clippy & Performance
This chapter covers production deployment strategies, Clippy lint configuration for code quality, performance optimization techniques, and monitoring best practices for Pierre.
Clippy Configuration
Pierre uses strict Clippy lints to maintain code quality with zero tolerance (deny level) for most warnings.
Source: Cargo.toml (lints section)
[lints.rust]
# STRICT UNSAFE CODE POLICY: Zero tolerance
unsafe_code = "deny"
missing_docs = "warn"
[lints.clippy]
# Base configuration: Enable all clippy lint groups at DENY level
# Priority -1 ensures these are applied first, then specific overrides below
all = { level = "deny", priority = -1 }
pedantic = { level = "deny", priority = -1 }
nursery = { level = "deny", priority = -1 }
# Critical Denials - Error Handling Anti-Patterns
unwrap_used = "deny"
expect_used = "deny"
panic = "deny"
# Allowed Exceptions (type casts with proper validation)
cast_possible_truncation = "allow"
cast_sign_loss = "allow"
cast_precision_loss = "allow"
# Const fn suggestions - false positives with runtime methods
missing_const_for_fn = "allow"
# Structural patterns - validated separately
struct_excessive_bools = "allow"
too_many_lines = "allow"
significant_drop_tightening = "allow"
# Additional code quality lints
clone_on_copy = "warn"
redundant_clone = "warn"
Lint configuration syntax (TOML inline tables):
{ level = "deny", priority = -1 }- Table syntax with priority ordering- Priority
-1means these base rules apply first, allowing specific overrides - Simple values like
"deny"or"allow"work for single-priority lints
Lint categories:
- all: Enable all Clippy lints (deny level = build errors)
- pedantic: Extra pedantic lints for code quality
- nursery: Experimental lints being tested
- Denials:
unwrap_used,paniccause build failures
Why deny unwrap/expect: Prevents runtime panics in production. Use ? operator, .unwrap_or(), or proper error handling instead.
Why deny unsafe: Pierre has a zero-unsafe policy with only one approved exception (src/health.rs for Windows FFI).
Production Deployment
Pierre deployment architecture:
┌──────────────┐
│ Nginx │ (Reverse proxy, TLS termination)
└──────┬───────┘
│
┌──────▼───────┐
│ Pierre │ (Rust binary, multiple instances)
│ Server │
└──────┬───────┘
│
┌──────▼───────┐
│ PostgreSQL │ (Primary database)
└──────────────┘
Deployment checklist:
- Environment variables: Set
DATABASE_URL,JWT_SECRET,OAUTH_*vars - TLS certificates: Configure HTTPS with Let’s Encrypt
- Database migrations: Run
sqlx migrate run - Connection pooling: Set
DATABASE_MAX_CONNECTIONS=20 - Logging: Configure
RUST_LOG=info - Monitoring: Enable Prometheus metrics endpoint
Performance Optimization
Database connection pooling:
#![allow(unused)]
fn main() {
let pool = PgPoolOptions::new()
.max_connections(20)
.acquire_timeout(Duration::from_secs(3))
.connect(&database_url)
.await?;
}
Query optimization:
- Indexes: Create indexes on
user_id,provider,activity_date - Prepared statements: Use SQLx compile-time verification
- Batch operations: Insert multiple activities in single transaction
- Connection reuse: Pool connections, avoid per-request connections
Async runtime optimization:
[dependencies]
tokio = { version = "1", features = ["full"] }
Tokio configuration:
- Worker threads: Default = CPU cores
- Blocking threads: Separate pool for blocking operations
- Stack size: Increase if deep recursion needed
Monitoring
Metrics to track:
- Request latency: P50, P95, P99 response times
- Error rate: 4xx and 5xx responses per endpoint
- Database connections: Active, idle, waiting
- Memory usage: RSS, heap allocation
- OAuth success rate: Connection success vs failures
Logging best practices:
#![allow(unused)]
fn main() {
tracing::info!(
user_id = %user_id,
provider = %provider,
activities_count = activities.len(),
"Successfully fetched activities"
);
}
Security Hardening
Production security:
- TLS only: Redirect HTTP to HTTPS
- CORS restrictions: Whitelist allowed origins
- Rate limiting: IP-based limits for public endpoints
- Input validation: Validate all user inputs
- SQL injection prevention: Use parameterized queries (SQLx)
- Secret management: Use environment variables or vault
- Audit logging: Log all authentication attempts
Environment configuration:
# Production environment variables
export DATABASE_URL="postgresql://user:pass@localhost/pierre"
export JWT_SECRET="$(openssl rand -base64 32)"
export RUST_LOG="info"
export HTTP_PORT="8081"
export CORS_ALLOWED_ORIGINS="https://app.pierre.ai"
Scaling Strategies
Horizontal scaling:
- Load balancer: Nginx/HAProxy distributes requests
- Multiple instances: Run 2-4 Pierre servers behind load balancer
- Session affinity: Not required (stateless JWT authentication)
Database scaling:
- Read replicas: Offload read-heavy queries
- Connection pooling: Limit connections per instance
- Caching: Redis for frequently accessed data
Performance targets:
- API latency: P95 < 200ms
- Database queries: P95 < 50ms
- OAuth flow: Complete in < 5 seconds
- Throughput: 1000 req/sec per instance
Key Takeaways
- Clippy lints: Strict lints (
denyunwrap, panic, todo) prevent common errors. - Connection pooling: Reuse database connections for performance.
- Deployment architecture: Nginx → Pierre (multiple instances) → PostgreSQL.
- Monitoring: Track latency, errors, connections, memory.
- Security hardening: TLS, CORS, rate limiting, input validation.
- Horizontal scaling: Load balancer + multiple stateless instances.
- Environment config: Use env vars for secrets and configuration.
End of Part VII: Testing & Deployment
You’ve completed the testing and deployment section. You now understand:
- Testing framework with synthetic data (Chapter 23)
- Design system and templates (Chapter 24)
- Production deployment and performance (Chapter 25)
Next: Appendix A: Rust Idioms Reference - Quick reference for Rust idioms used throughout Pierre.