Production Deployment
Building for Production
Preparing a Hypermodern application for production involves optimization, security hardening, and creating deployable artifacts that can run efficiently in production environments.
Production Build Process
# Basic production build
hypermodern build
# Advanced build with custom options
hypermodern build \
--output dist \
--minify \
--tree-shake \
--no-source-maps \
--docker \
--env production
The build process performs several optimizations:
class ProductionBuilder {
final BuildConfig _config;
final CodeOptimizer _optimizer;
final AssetProcessor _assetProcessor;
final SecurityHardener _securityHardener;
ProductionBuilder({
required BuildConfig config,
required CodeOptimizer optimizer,
required AssetProcessor assetProcessor,
required SecurityHardener securityHardener,
}) : _config = config,
_optimizer = optimizer,
_assetProcessor = assetProcessor,
_securityHardener = securityHardener;
Future<BuildResult> build() async {
print('🏗️ Building for production...');
final stopwatch = Stopwatch()..start();
try {
// Clean output directory
await _cleanOutputDirectory();
// Compile Dart code
final compiledCode = await _compileCode();
// Optimize code
final optimizedCode = await _optimizer.optimize(compiledCode);
// Process assets
final processedAssets = await _assetProcessor.process();
// Apply security hardening
await _securityHardener.harden(optimizedCode);
// Generate deployment artifacts
final artifacts = await _generateArtifacts(optimizedCode, processedAssets);
// Create Docker image if requested
if (_config.generateDocker) {
await _generateDockerFiles(artifacts);
}
// Generate deployment scripts
await _generateDeploymentScripts(artifacts);
stopwatch.stop();
return BuildResult(
success: true,
artifacts: artifacts,
buildTime: stopwatch.elapsed,
outputSize: await _calculateOutputSize(artifacts),
);
} catch (e) {
return BuildResult(
success: false,
error: e.toString(),
buildTime: stopwatch.elapsed,
);
}
}
Future<void> _cleanOutputDirectory() async {
final outputDir = Directory(_config.outputDirectory);
if (await outputDir.exists()) {
await outputDir.delete(recursive: true);
}
await outputDir.create(recursive: true);
}
Future<CompiledCode> _compileCode() async {
print('📦 Compiling Dart code...');
// Compile to native executable
final result = await Process.run('dart', [
'compile',
'exe',
'lib/main.dart',
'-o',
'${_config.outputDirectory}/app',
if (_config.optimize) '--optimization-level=2',
if (!_config.includeSourceMaps) '--no-source-maps',
]);
if (result.exitCode != 0) {
throw BuildException('Compilation failed: ${result.stderr}');
}
return CompiledCode(
executablePath: '${_config.outputDirectory}/app',
size: await File('${_config.outputDirectory}/app').length(),
);
}
Future<List<BuildArtifact>> _generateArtifacts(
CompiledCode code,
List<ProcessedAsset> assets,
) async {
final artifacts = <BuildArtifact>[];
// Main executable
artifacts.add(BuildArtifact(
name: 'app',
type: ArtifactType.executable,
path: code.executablePath,
size: code.size,
));
// Configuration files
artifacts.add(await _generateProductionConfig());
// Database migrations
artifacts.addAll(await _packageMigrations());
// Static assets
for (final asset in assets) {
artifacts.add(BuildArtifact(
name: asset.name,
type: ArtifactType.asset,
path: asset.outputPath,
size: asset.size,
));
}
return artifacts;
}
Future<BuildArtifact> _generateProductionConfig() async {
final config = ProductionConfig(
server: ServerConfig(
httpPort: int.fromEnvironment('HTTP_PORT', defaultValue: 8080),
wsPort: int.fromEnvironment('WS_PORT', defaultValue: 8082),
tcpPort: int.fromEnvironment('TCP_PORT', defaultValue: 8081),
bindAddress: const String.fromEnvironment('BIND_ADDRESS', defaultValue: '0.0.0.0'),
maxConnections: int.fromEnvironment('MAX_CONNECTIONS', defaultValue: 1000),
requestTimeout: Duration(
seconds: int.fromEnvironment('REQUEST_TIMEOUT', defaultValue: 30),
),
),
database: DatabaseConfig(
url: const String.fromEnvironment('DATABASE_URL'),
maxConnections: int.fromEnvironment('DB_MAX_CONNECTIONS', defaultValue: 20),
connectionTimeout: Duration(
seconds: int.fromEnvironment('DB_CONNECTION_TIMEOUT', defaultValue: 10),
),
),
security: SecurityConfig(
jwtSecret: const String.fromEnvironment('JWT_SECRET'),
corsOrigins: const String.fromEnvironment('CORS_ORIGINS', defaultValue: '*')
.split(','),
rateLimitEnabled: const bool.fromEnvironment('RATE_LIMIT_ENABLED', defaultValue: true),
rateLimitRequests: int.fromEnvironment('RATE_LIMIT_REQUESTS', defaultValue: 100),
),
logging: LoggingConfig(
level: const String.fromEnvironment('LOG_LEVEL', defaultValue: 'info'),
format: const String.fromEnvironment('LOG_FORMAT', defaultValue: 'json'),
output: const String.fromEnvironment('LOG_OUTPUT', defaultValue: 'stdout'),
),
);
final configPath = '${_config.outputDirectory}/config.yaml';
await File(configPath).writeAsString(yaml.encode(config.toJson()));
return BuildArtifact(
name: 'config.yaml',
type: ArtifactType.config,
path: configPath,
size: await File(configPath).length(),
);
}
}
class BuildConfig {
final String outputDirectory;
final bool optimize;
final bool minify;
final bool treeShake;
final bool includeSourceMaps;
final bool generateDocker;
final String environment;
BuildConfig({
this.outputDirectory = 'dist',
this.optimize = true,
this.minify = true,
this.treeShake = true,
this.includeSourceMaps = false,
this.generateDocker = false,
this.environment = 'production',
});
}
Code Optimization
class CodeOptimizer {
final OptimizationConfig _config;
CodeOptimizer(this._config);
Future<CompiledCode> optimize(CompiledCode code) async {
print('⚡ Optimizing code...');
var optimizedCode = code;
// Dead code elimination
if (_config.eliminateDeadCode) {
optimizedCode = await _eliminateDeadCode(optimizedCode);
}
// Tree shaking
if (_config.treeShake) {
optimizedCode = await _performTreeShaking(optimizedCode);
}
// Binary optimization
if (_config.optimizeBinary) {
optimizedCode = await _optimizeBinary(optimizedCode);
}
// Compression
if (_config.compress) {
optimizedCode = await _compressExecutable(optimizedCode);
}
return optimizedCode;
}
Future<CompiledCode> _eliminateDeadCode(CompiledCode code) async {
// Analyze code to find unused functions and classes
final analyzer = DeadCodeAnalyzer();
final unusedSymbols = await analyzer.findUnusedSymbols(code);
print('🗑️ Eliminating ${unusedSymbols.length} unused symbols');
// Remove unused code (this would be more complex in practice)
return code.copyWith(
size: (code.size * 0.95).round(), // Estimated size reduction
);
}
Future<CompiledCode> _performTreeShaking(CompiledCode code) async {
print('🌳 Performing tree shaking...');
// Tree shaking removes unused imports and dependencies
// This would integrate with Dart's tree shaking capabilities
return code.copyWith(
size: (code.size * 0.9).round(), // Estimated size reduction
);
}
Future<CompiledCode> _optimizeBinary(CompiledCode code) async {
print('🔧 Optimizing binary...');
// Apply binary-level optimizations
final result = await Process.run('strip', [code.executablePath]);
if (result.exitCode == 0) {
final newSize = await File(code.executablePath).length();
return code.copyWith(size: newSize);
}
return code;
}
Future<CompiledCode> _compressExecutable(CompiledCode code) async {
print('📦 Compressing executable...');
// Use UPX or similar tool to compress the executable
final result = await Process.run('upx', [
'--best',
'--lzma',
code.executablePath,
]);
if (result.exitCode == 0) {
final newSize = await File(code.executablePath).length();
print('📉 Compressed from ${_formatBytes(code.size)} to ${_formatBytes(newSize)}');
return code.copyWith(size: newSize);
}
return code;
}
String _formatBytes(int bytes) {
if (bytes < 1024) return '${bytes}B';
if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)}KB';
return '${(bytes / (1024 * 1024)).toStringAsFixed(1)}MB';
}
}
Docker and Containerization
Multi-Stage Docker Build
# Dockerfile
# Build stage
FROM dart:3.2-sdk AS build
# Set working directory
WORKDIR /app
# Copy pubspec files
COPY pubspec.yaml pubspec.lock ./
# Install dependencies
RUN dart pub get
# Copy source code
COPY . .
# Generate code
RUN dart run hypermodern_cli:main generate
# Build application
RUN dart compile exe lib/main.dart -o server
# Runtime stage
FROM debian:bookworm-slim AS runtime
# Install runtime dependencies
RUN apt-get update && apt-get install -y \
ca-certificates \
curl \
&& rm -rf /var/lib/apt/lists/*
# Create app user
RUN useradd -r -s /bin/false -m -d /app app
# Set working directory
WORKDIR /app
# Copy built application
COPY --from=build /app/server ./
COPY --from=build /app/config ./config/
COPY --from=build /app/migrations ./migrations/
# Copy startup script
COPY docker/entrypoint.sh ./
RUN chmod +x entrypoint.sh
# Change ownership
RUN chown -R app:app /app
# Switch to app user
USER app
# Expose ports
EXPOSE 8080 8082 8081
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
# Start application
ENTRYPOINT ["./entrypoint.sh"]
Docker Compose for Development
# docker-compose.yml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
target: runtime
ports:
- "8080:8080" # HTTP
- "8082:8082" # WebSocket
- "8081:8081" # TCP
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/hypermodern
- REDIS_URL=redis://redis:6379
- JWT_SECRET=your-secret-key-here
- LOG_LEVEL=info
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
networks:
- hypermodern
db:
image: postgres:15-alpine
environment:
- POSTGRES_DB=hypermodern
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
- ./migrations:/docker-entrypoint-initdb.d
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
networks:
- hypermodern
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- hypermodern
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/ssl:/etc/nginx/ssl
depends_on:
- app
networks:
- hypermodern
volumes:
postgres_data:
redis_data:
networks:
hypermodern:
driver: bridge
Kubernetes Deployment
# k8s/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: hypermodern
---
# k8s/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: hypermodern-config
namespace: hypermodern
data:
HTTP_PORT: "8080"
WS_PORT: "8082"
TCP_PORT: "8081"
LOG_LEVEL: "info"
LOG_FORMAT: "json"
---
# k8s/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: hypermodern-secrets
namespace: hypermodern
type: Opaque
data:
DATABASE_URL: cG9zdGdyZXNxbDovL3VzZXI6cGFzc0BkYjozNDMyL2h5cGVybW9kZXJu
JWT_SECRET: eW91ci1qd3Qtc2VjcmV0LWtleQ==
REDIS_URL: cmVkaXM6Ly9yZWRpczozNjM3OQ==
---
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hypermodern-app
namespace: hypermodern
labels:
app: hypermodern
spec:
replicas: 3
selector:
matchLabels:
app: hypermodern
template:
metadata:
labels:
app: hypermodern
spec:
containers:
- name: hypermodern
image: hypermodern:latest
ports:
- containerPort: 8080
name: http
- containerPort: 8082
name: websocket
- containerPort: 8081
name: tcp
envFrom:
- configMapRef:
name: hypermodern-config
- secretRef:
name: hypermodern-secrets
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
---
# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
name: hypermodern-service
namespace: hypermodern
spec:
selector:
app: hypermodern
ports:
- name: http
port: 80
targetPort: 8080
- name: websocket
port: 8082
targetPort: 8082
- name: tcp
port: 8081
targetPort: 8081
type: ClusterIP
---
# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hypermodern-ingress
namespace: hypermodern
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/websocket-services: "hypermodern-service"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- api.yourdomain.com
secretName: hypermodern-tls
rules:
- host: api.yourdomain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: hypermodern-service
port:
number: 80
---
# k8s/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: hypermodern-hpa
namespace: hypermodern
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: hypermodern-app
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
Deployment Strategies
Blue-Green Deployment
class BlueGreenDeployment {
final KubernetesClient _k8sClient;
final LoadBalancer _loadBalancer;
final HealthChecker _healthChecker;
BlueGreenDeployment({
required KubernetesClient k8sClient,
required LoadBalancer loadBalancer,
required HealthChecker healthChecker,
}) : _k8sClient = k8sClient,
_loadBalancer = loadBalancer,
_healthChecker = healthChecker;
Future<DeploymentResult> deploy({
required String newVersion,
required Duration healthCheckTimeout,
required Duration rollbackTimeout,
}) async {
print('🚀 Starting blue-green deployment to version $newVersion');
try {
// Determine current and new environments
final currentEnv = await _getCurrentEnvironment();
final newEnv = currentEnv == 'blue' ? 'green' : 'blue';
print('📍 Current environment: $currentEnv');
print('🎯 Deploying to: $newEnv');
// Deploy to new environment
await _deployToEnvironment(newEnv, newVersion);
// Wait for deployment to be ready
await _waitForDeploymentReady(newEnv);
// Perform health checks
final healthCheckResult = await _performHealthChecks(newEnv, healthCheckTimeout);
if (!healthCheckResult.healthy) {
throw DeploymentException('Health checks failed: ${healthCheckResult.errors}');
}
// Switch traffic to new environment
await _switchTraffic(currentEnv, newEnv);
// Verify traffic switch
await _verifyTrafficSwitch(newEnv);
// Keep old environment for rollback window
await _scheduleOldEnvironmentCleanup(currentEnv, rollbackTimeout);
return DeploymentResult(
success: true,
version: newVersion,
environment: newEnv,
previousEnvironment: currentEnv,
);
} catch (e) {
print('❌ Deployment failed: $e');
// Attempt rollback if traffic was switched
await _attemptRollback();
return DeploymentResult(
success: false,
error: e.toString(),
);
}
}
Future<void> _deployToEnvironment(String environment, String version) async {
print('📦 Deploying version $version to $environment environment');
// Update deployment with new image
await _k8sClient.updateDeployment(
name: 'hypermodern-app-$environment',
image: 'hypermodern:$version',
);
// Scale up if needed
await _k8sClient.scaleDeployment(
name: 'hypermodern-app-$environment',
replicas: 3,
);
}
Future<void> _waitForDeploymentReady(String environment) async {
print('⏳ Waiting for deployment to be ready...');
const maxWaitTime = Duration(minutes: 10);
const checkInterval = Duration(seconds: 10);
final deadline = DateTime.now().add(maxWaitTime);
while (DateTime.now().isBefore(deadline)) {
final ready = await _k8sClient.isDeploymentReady('hypermodern-app-$environment');
if (ready) {
print('✅ Deployment is ready');
return;
}
await Future.delayed(checkInterval);
}
throw DeploymentException('Deployment did not become ready within $maxWaitTime');
}
Future<HealthCheckResult> _performHealthChecks(
String environment,
Duration timeout,
) async {
print('🏥 Performing health checks...');
final endpoints = await _k8sClient.getServiceEndpoints('hypermodern-service-$environment');
final results = <String, bool>{};
final errors = <String>[];
for (final endpoint in endpoints) {
try {
final healthy = await _healthChecker.checkEndpoint(
endpoint,
timeout: timeout,
);
results[endpoint] = healthy;
if (!healthy) {
errors.add('Health check failed for $endpoint');
}
} catch (e) {
results[endpoint] = false;
errors.add('Health check error for $endpoint: $e');
}
}
final allHealthy = results.values.every((healthy) => healthy);
return HealthCheckResult(
healthy: allHealthy,
results: results,
errors: errors,
);
}
Future<void> _switchTraffic(String fromEnv, String toEnv) async {
print('🔄 Switching traffic from $fromEnv to $toEnv');
// Update load balancer configuration
await _loadBalancer.updateTargets(
serviceName: 'hypermodern-service',
newTargets: await _k8sClient.getServiceEndpoints('hypermodern-service-$toEnv'),
);
// Update ingress to point to new service
await _k8sClient.updateIngress(
name: 'hypermodern-ingress',
serviceName: 'hypermodern-service-$toEnv',
);
}
Future<void> _verifyTrafficSwitch(String environment) async {
print('🔍 Verifying traffic switch...');
// Make test requests to verify traffic is going to new environment
final testClient = HttpClient();
for (int i = 0; i < 10; i++) {
final response = await testClient.get('https://api.yourdomain.com/health');
final version = response.headers['x-app-version']?.first;
if (version == null) {
throw DeploymentException('Unable to determine app version from response');
}
// Verify we're hitting the new environment
// This would check some environment-specific identifier
}
print('✅ Traffic switch verified');
}
}
Canary Deployment
class CanaryDeployment {
final KubernetesClient _k8sClient;
final MetricsCollector _metricsCollector;
final AlertManager _alertManager;
CanaryDeployment({
required KubernetesClient k8sClient,
required MetricsCollector metricsCollector,
required AlertManager alertManager,
}) : _k8sClient = k8sClient,
_metricsCollector = metricsCollector,
_alertManager = alertManager;
Future<DeploymentResult> deploy({
required String newVersion,
required List<CanaryStage> stages,
required Duration stageInterval,
required CanaryMetrics successCriteria,
}) async {
print('🐤 Starting canary deployment to version $newVersion');
try {
// Deploy canary version
await _deployCanaryVersion(newVersion);
// Execute canary stages
for (final stage in stages) {
await _executeCanaryStage(stage, stageInterval, successCriteria);
}
// Promote canary to production
await _promoteCanaryToProduction(newVersion);
return DeploymentResult(
success: true,
version: newVersion,
deploymentType: 'canary',
);
} catch (e) {
print('❌ Canary deployment failed: $e');
// Rollback canary
await _rollbackCanary();
return DeploymentResult(
success: false,
error: e.toString(),
);
}
}
Future<void> _executeCanaryStage(
CanaryStage stage,
Duration interval,
CanaryMetrics successCriteria,
) async {
print('📊 Executing canary stage: ${stage.trafficPercentage}% traffic');
// Update traffic split
await _updateTrafficSplit(stage.trafficPercentage);
// Wait for stage interval
await Future.delayed(interval);
// Collect metrics
final metrics = await _collectCanaryMetrics(interval);
// Evaluate success criteria
final evaluation = _evaluateMetrics(metrics, successCriteria);
if (!evaluation.success) {
throw CanaryException('Stage failed: ${evaluation.reason}');
}
print('✅ Stage completed successfully');
}
Future<void> _updateTrafficSplit(int canaryPercentage) async {
await _k8sClient.updateTrafficSplit(
serviceName: 'hypermodern-service',
canaryPercentage: canaryPercentage,
stablePercentage: 100 - canaryPercentage,
);
}
Future<CanaryMetricsResult> _collectCanaryMetrics(Duration period) async {
final endTime = DateTime.now();
final startTime = endTime.subtract(period);
final [
canaryMetrics,
stableMetrics,
] = await Future.wait([
_metricsCollector.getMetrics(
service: 'hypermodern-canary',
startTime: startTime,
endTime: endTime,
),
_metricsCollector.getMetrics(
service: 'hypermodern-stable',
startTime: startTime,
endTime: endTime,
),
]);
return CanaryMetricsResult(
canary: canaryMetrics,
stable: stableMetrics,
period: period,
);
}
MetricsEvaluation _evaluateMetrics(
CanaryMetricsResult metrics,
CanaryMetrics criteria,
) {
// Error rate check
if (metrics.canary.errorRate > criteria.maxErrorRate) {
return MetricsEvaluation(
success: false,
reason: 'Error rate too high: ${metrics.canary.errorRate}% > ${criteria.maxErrorRate}%',
);
}
// Response time check
if (metrics.canary.averageResponseTime > criteria.maxResponseTime) {
return MetricsEvaluation(
success: false,
reason: 'Response time too high: ${metrics.canary.averageResponseTime}ms > ${criteria.maxResponseTime}ms',
);
}
// Comparison with stable version
final errorRateIncrease = metrics.canary.errorRate - metrics.stable.errorRate;
if (errorRateIncrease > criteria.maxErrorRateIncrease) {
return MetricsEvaluation(
success: false,
reason: 'Error rate increase too high: ${errorRateIncrease}%',
);
}
return MetricsEvaluation(success: true);
}
}
class CanaryStage {
final int trafficPercentage;
final Duration duration;
CanaryStage({
required this.trafficPercentage,
required this.duration,
});
}
class CanaryMetrics {
final double maxErrorRate;
final int maxResponseTime;
final double maxErrorRateIncrease;
CanaryMetrics({
required this.maxErrorRate,
required this.maxResponseTime,
required this.maxErrorRateIncrease,
});
}
Monitoring and Logging
Production Monitoring Setup
class ProductionMonitoring {
final PrometheusClient _prometheus;
final GrafanaClient _grafana;
final AlertManagerClient _alertManager;
final LogAggregator _logAggregator;
ProductionMonitoring({
required PrometheusClient prometheus,
required GrafanaClient grafana,
required AlertManagerClient alertManager,
required LogAggregator logAggregator,
}) : _prometheus = prometheus,
_grafana = grafana,
_alertManager = alertManager,
_logAggregator = logAggregator;
Future<void> setupMonitoring() async {
print('📊 Setting up production monitoring...');
// Configure Prometheus metrics
await _setupPrometheusMetrics();
// Create Grafana dashboards
await _setupGrafanaDashboards();
// Configure alerts
await _setupAlerts();
// Configure log aggregation
await _setupLogAggregation();
print('✅ Monitoring setup complete');
}
Future<void> _setupPrometheusMetrics() async {
// Application metrics
await _prometheus.createMetric(MetricDefinition(
name: 'hypermodern_requests_total',
type: MetricType.counter,
help: 'Total number of requests',
labels: ['method', 'endpoint', 'status', 'protocol'],
));
await _prometheus.createMetric(MetricDefinition(
name: 'hypermodern_request_duration_seconds',
type: MetricType.histogram,
help: 'Request duration in seconds',
labels: ['method', 'endpoint', 'protocol'],
buckets: [0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0],
));
await _prometheus.createMetric(MetricDefinition(
name: 'hypermodern_active_connections',
type: MetricType.gauge,
help: 'Number of active connections',
labels: ['protocol'],
));
await _prometheus.createMetric(MetricDefinition(
name: 'hypermodern_database_connections',
type: MetricType.gauge,
help: 'Number of database connections',
labels: ['state'], // active, idle, waiting
));
// Business metrics
await _prometheus.createMetric(MetricDefinition(
name: 'hypermodern_users_active',
type: MetricType.gauge,
help: 'Number of active users',
));
await _prometheus.createMetric(MetricDefinition(
name: 'hypermodern_operations_total',
type: MetricType.counter,
help: 'Total number of business operations',
labels: ['operation', 'status'],
));
}
Future<void> _setupGrafanaDashboards() async {
// Application overview dashboard
await _grafana.createDashboard(DashboardDefinition(
title: 'Hypermodern Application Overview',
panels: [
PanelDefinition(
title: 'Request Rate',
type: PanelType.graph,
query: 'rate(hypermodern_requests_total[5m])',
),
PanelDefinition(
title: 'Response Time',
type: PanelType.graph,
query: 'histogram_quantile(0.95, rate(hypermodern_request_duration_seconds_bucket[5m]))',
),
PanelDefinition(
title: 'Error Rate',
type: PanelType.singleStat,
query: 'rate(hypermodern_requests_total{status=~"5.."}[5m]) / rate(hypermodern_requests_total[5m]) * 100',
),
PanelDefinition(
title: 'Active Connections by Protocol',
type: PanelType.graph,
query: 'hypermodern_active_connections',
),
],
));
// Infrastructure dashboard
await _grafana.createDashboard(DashboardDefinition(
title: 'Hypermodern Infrastructure',
panels: [
PanelDefinition(
title: 'CPU Usage',
type: PanelType.graph,
query: 'rate(container_cpu_usage_seconds_total{pod=~"hypermodern-.*"}[5m]) * 100',
),
PanelDefinition(
title: 'Memory Usage',
type: PanelType.graph,
query: 'container_memory_usage_bytes{pod=~"hypermodern-.*"}',
),
PanelDefinition(
title: 'Database Connections',
type: PanelType.graph,
query: 'hypermodern_database_connections',
),
],
));
}
Future<void> _setupAlerts() async {
// High error rate alert
await _alertManager.createAlert(AlertRule(
name: 'HighErrorRate',
expression: 'rate(hypermodern_requests_total{status=~"5.."}[5m]) / rate(hypermodern_requests_total[5m]) > 0.05',
duration: Duration(minutes: 2),
severity: AlertSeverity.critical,
summary: 'High error rate detected',
description: 'Error rate is above 5% for more than 2 minutes',
actions: [
AlertAction.email(['ops@company.com']),
AlertAction.slack('#alerts'),
AlertAction.pagerDuty('hypermodern-service'),
],
));
// High response time alert
await _alertManager.createAlert(AlertRule(
name: 'HighResponseTime',
expression: 'histogram_quantile(0.95, rate(hypermodern_request_duration_seconds_bucket[5m])) > 2',
duration: Duration(minutes: 5),
severity: AlertSeverity.warning,
summary: 'High response time detected',
description: '95th percentile response time is above 2 seconds',
actions: [
AlertAction.slack('#performance'),
],
));
// Database connection pool exhaustion
await _alertManager.createAlert(AlertRule(
name: 'DatabaseConnectionPoolExhaustion',
expression: 'hypermodern_database_connections{state="waiting"} > 0',
duration: Duration(minutes: 1),
severity: AlertSeverity.warning,
summary: 'Database connection pool under pressure',
description: 'Requests are waiting for database connections',
actions: [
AlertAction.slack('#database'),
],
));
}
Future<void> _setupLogAggregation() async {
// Configure structured logging
await _logAggregator.configureSource(LogSource(
name: 'hypermodern-app',
pattern: '/var/log/hypermodern/*.log',
parser: LogParser.json,
fields: {
'timestamp': 'timestamp',
'level': 'level',
'message': 'message',
'trace_id': 'trace_id',
'user_id': 'user_id',
'endpoint': 'endpoint',
'protocol': 'protocol',
},
));
// Create log-based alerts
await _logAggregator.createAlert(LogAlert(
name: 'DatabaseConnectionErrors',
query: 'level:ERROR AND message:"database connection"',
threshold: 10,
timeWindow: Duration(minutes: 5),
actions: [
AlertAction.slack('#database'),
],
));
}
}
Application Metrics Integration
class MetricsMiddleware implements Middleware {
final PrometheusClient _prometheus;
final Counter _requestsTotal;
final Histogram _requestDuration;
final Gauge _activeConnections;
MetricsMiddleware(this._prometheus)
: _requestsTotal = _prometheus.getCounter('hypermodern_requests_total'),
_requestDuration = _prometheus.getHistogram('hypermodern_request_duration_seconds'),
_activeConnections = _prometheus.getGauge('hypermodern_active_connections');
@override
Future<dynamic> handle(
dynamic request,
Future<dynamic> Function(dynamic) next,
) async {
final stopwatch = Stopwatch()..start();
final protocol = request.protocol as String;
final endpoint = request.endpoint as String;
// Increment active connections
_activeConnections.inc(labels: {'protocol': protocol});
try {
final response = await next(request);
stopwatch.stop();
// Record successful request
_requestsTotal.inc(labels: {
'method': request.method ?? 'UNKNOWN',
'endpoint': endpoint,
'status': '200',
'protocol': protocol,
});
_requestDuration.observe(
stopwatch.elapsedMilliseconds / 1000.0,
labels: {
'method': request.method ?? 'UNKNOWN',
'endpoint': endpoint,
'protocol': protocol,
},
);
return response;
} catch (e) {
stopwatch.stop();
// Record failed request
final statusCode = _getStatusCodeFromException(e);
_requestsTotal.inc(labels: {
'method': request.method ?? 'UNKNOWN',
'endpoint': endpoint,
'status': statusCode.toString(),
'protocol': protocol,
});
_requestDuration.observe(
stopwatch.elapsedMilliseconds / 1000.0,
labels: {
'method': request.method ?? 'UNKNOWN',
'endpoint': endpoint,
'protocol': protocol,
},
);
rethrow;
} finally {
// Decrement active connections
_activeConnections.dec(labels: {'protocol': protocol});
}
}
int _getStatusCodeFromException(dynamic exception) {
if (exception is NotFoundException) return 404;
if (exception is ValidationException) return 400;
if (exception is UnauthorizedException) return 401;
if (exception is ForbiddenException) return 403;
if (exception is RateLimitExceededException) return 429;
return 500;
}
}
Scaling Considerations
Horizontal Pod Autoscaling
# k8s/hpa-advanced.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: hypermodern-hpa
namespace: hypermodern
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: hypermodern-app
minReplicas: 3
maxReplicas: 50
metrics:
# CPU-based scaling
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
# Memory-based scaling
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
# Custom metrics scaling
- type: Pods
pods:
metric:
name: hypermodern_active_connections
target:
type: AverageValue
averageValue: "100"
- type: Object
object:
metric:
name: hypermodern_queue_length
target:
type: Value
value: "1000"
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 50
periodSeconds: 60
- type: Pods
value: 5
periodSeconds: 60
selectPolicy: Max
Load Balancing Configuration
# nginx/nginx.conf
upstream hypermodern_http {
least_conn;
server hypermodern-app-1:8080 max_fails=3 fail_timeout=30s;
server hypermodern-app-2:8080 max_fails=3 fail_timeout=30s;
server hypermodern-app-3:8080 max_fails=3 fail_timeout=30s;
keepalive 32;
}
upstream hypermodern_websocket {
ip_hash; # Sticky sessions for WebSocket
server hypermodern-app-1:8082 max_fails=3 fail_timeout=30s;
server hypermodern-app-2:8082 max_fails=3 fail_timeout=30s;
server hypermodern-app-3:8082 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
listen 443 ssl http2;
server_name api.yourdomain.com;
# SSL configuration
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
ssl_prefer_server_ciphers off;
# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
# HTTP API
location / {
proxy_pass http://hypermodern_http;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Timeouts
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# Buffering
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
# WebSocket upgrade
location /ws {
proxy_pass http://hypermodern_websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket timeouts
proxy_connect_timeout 7d;
proxy_send_timeout 7d;
proxy_read_timeout 7d;
}
# Health check endpoint
location /health {
access_log off;
proxy_pass http://hypermodern_http;
proxy_set_header Host $host;
}
}
# TCP load balancing (requires stream module)
stream {
upstream hypermodern_tcp {
least_conn;
server hypermodern-app-1:8081 max_fails=3 fail_timeout=30s;
server hypermodern-app-2:8081 max_fails=3 fail_timeout=30s;
server hypermodern-app-3:8081 max_fails=3 fail_timeout=30s;
}
server {
listen 8081;
proxy_pass hypermodern_tcp;
proxy_timeout 1s;
proxy_responses 1;
error_log /var/log/nginx/tcp.log;
}
}
What's Next
You now have comprehensive knowledge of production deployment for Hypermodern applications, including build optimization, containerization, deployment strategies, monitoring, and scaling. The next chapter will provide real-world examples, showing you how to build complete applications like chat systems, API gateways, and IoT platforms using everything you've learned throughout this book.
No Comments