Pular para o conteúdo principal

Componentes de Infraestrutura

O edgeProxy inclui componentes de infraestrutura prontos para produção para confiabilidade e observabilidade.

Graceful Shutdown​

Trata sinais SIGTERM e Ctrl+C, permitindo que conexões em andamento completem antes do shutdown.

use edgeproxy::infrastructure::{ShutdownController, shutdown_signal};

// Criar controller
let shutdown = ShutdownController::new();

// Rastrear conexões ativas com guards RAII
let _guard = shutdown.connection_guard();
// Conexão é automaticamente decrementada quando guard é dropado

// Aguardar sinal de shutdown
shutdown_signal().await;

// Drenar conexões com timeout
shutdown.wait_for_drain(Duration::from_secs(30)).await;

Configuração​

VariávelPadrãoDescrição
EDGEPROXY_SHUTDOWN_TIMEOUT_SECS30Tempo máximo para aguardar drenagem de conexões

Como Funciona​

Fluxo de Graceful Shutdown

  1. Sinal recebido (SIGTERM/Ctrl+C)
  2. Para de aceitar novas conexões
  3. Aguarda conexões ativas completarem (até timeout)
  4. Força fechamento das conexões restantes
  5. Sai de forma limpa

Rate Limiting​

Rate limiting por token bucket por IP do cliente para prevenir abuso.

use edgeproxy::infrastructure::{RateLimiter, RateLimitConfig};

let limiter = RateLimiter::new(RateLimitConfig {
max_requests: 100, // Requisições por janela
window: Duration::from_secs(1),
burst_size: 10, // Burst inicial permitido
});

// Verificar se requisição é permitida
if limiter.check(client_ip) {
// Processar requisição
} else {
// Retornar 429 Too Many Requests
}

// Verificar tokens restantes
let remaining = limiter.remaining(client_ip);

Configuração​

VariávelPadrãoDescrição
EDGEPROXY_RATE_LIMIT_ENABLEDfalseHabilitar rate limiting
EDGEPROXY_RATE_LIMIT_MAX_REQUESTS100Máximo de requisições por janela
EDGEPROXY_RATE_LIMIT_WINDOW_SECS1Janela de tempo em segundos
EDGEPROXY_RATE_LIMIT_BURST10Tamanho do burst (token bucket)

Algoritmo​

Algoritmo Token Bucket:
- Cada cliente começa com `burst_size` tokens
- Tokens são reabastecidos na taxa `max_requests / window`
- Cada requisição consome 1 token
- Requisição negada se não houver tokens disponíveis

Circuit Breaker​

Previne falhas em cascata bloqueando temporariamente requisições para backends com falha.

use edgeproxy::infrastructure::{CircuitBreaker, CircuitBreakerConfig};

let breaker = CircuitBreaker::new(CircuitBreakerConfig {
failure_threshold: 5, // Falhas antes de abrir
success_threshold: 3, // Sucessos para fechar
timeout: Duration::from_secs(30), // Tempo no estado aberto
});

// Verificar se requisição é permitida
if breaker.allow() {
match backend_request().await {
Ok(_) => breaker.record_success(),
Err(_) => breaker.record_failure(),
}
} else {
// Circuito está aberto, falha rápida
}

Estados​

EstadoDescriçãoComportamento
ClosedOperação normalTodas requisições passam
OpenBackend falhandoTodas requisições falham rápido
Half-OpenTestando recuperaçãoRequisições limitadas para testar backend

Transições de Estado​

         falhas >= threshold
Closed ─────────────────────────► Open
▲ │
│ sucessos >= threshold │ timeout expira
│ ▼
└──────────────────────────── Half-Open
│
│ falha
▼
Open

Configuração​

VariávelPadrãoDescrição
EDGEPROXY_CIRCUIT_BREAKER_ENABLEDfalseHabilitar circuit breaker
EDGEPROXY_CIRCUIT_FAILURE_THRESHOLD5Falhas para abrir circuito
EDGEPROXY_CIRCUIT_SUCCESS_THRESHOLD3Sucessos para fechar circuito
EDGEPROXY_CIRCUIT_TIMEOUT_SECS30Timeout no estado aberto

Health Checks Ativos​

Monitora proativamente a saúde dos backends com probes TCP ou HTTP.

use edgeproxy::infrastructure::{HealthChecker, HealthCheckConfig, HealthCheckType};

let checker = HealthChecker::new(
"backend-1".to_string(),
"10.50.1.1:8080".to_string(),
HealthCheckConfig {
check_type: HealthCheckType::Http {
path: "/health".to_string(),
expected_status: 200,
},
interval: Duration::from_secs(5),
timeout: Duration::from_secs(2),
healthy_threshold: 2,
unhealthy_threshold: 3,
},
);

// Iniciar health checks em background
checker.start();

// Obter status atual
let status = checker.status();
println!("Backend saudável: {}", status.is_healthy);

Tipos de Check​

TipoDescriçãoCaso de Uso
TCPVerificação simples de conexãoConectividade básica
HTTPHTTP GET com verificação de statusSaúde da aplicação

Configuração​

VariávelPadrãoDescrição
EDGEPROXY_HEALTH_CHECK_ENABLEDfalseHabilitar health checks ativos
EDGEPROXY_HEALTH_CHECK_INTERVAL_SECS5Intervalo de check
EDGEPROXY_HEALTH_CHECK_TIMEOUT_SECS2Timeout do check
EDGEPROXY_HEALTH_CHECK_TYPEtcpTipo de check: tcp ou http
EDGEPROXY_HEALTH_CHECK_PATH/healthPath do check HTTP
EDGEPROXY_HEALTH_HEALTHY_THRESHOLD2Sucessos para se tornar saudável
EDGEPROXY_HEALTH_UNHEALTHY_THRESHOLD3Falhas para se tornar não saudável

Connection Pooling​

Reutiliza conexões TCP para backends para melhorar performance.

use edgeproxy::infrastructure::{ConnectionPool, PoolConfig};

let pool = ConnectionPool::new(PoolConfig {
max_connections_per_backend: 10,
idle_timeout: Duration::from_secs(60),
max_lifetime: Duration::from_secs(300),
connect_timeout: Duration::from_secs(5),
});

// Adquirir uma conexão (reutiliza existente ou cria nova)
let conn = pool.acquire("backend-1", "10.50.1.1:8080").await?;

// Usar conexão...
// Conexão é retornada ao pool quando dropada

Configuração​

VariávelPadrãoDescrição
EDGEPROXY_POOL_ENABLEDfalseHabilitar connection pooling
EDGEPROXY_POOL_MAX_PER_BACKEND10Máximo de conexões por backend
EDGEPROXY_POOL_IDLE_TIMEOUT_SECS60Timeout de conexão ociosa
EDGEPROXY_POOL_MAX_LIFETIME_SECS300Tempo máximo de vida da conexão
EDGEPROXY_POOL_CONNECT_TIMEOUT_SECS5Timeout de conexão

Benefícios​

  • Latência reduzida (sem handshake TCP)
  • Carga reduzida no backend (menos conexões)
  • Melhor utilização de recursos

Métricas Prometheus​

Exporta métricas em formato Prometheus para monitoramento e alertas.

use edgeproxy::adapters::outbound::PrometheusMetricsStore;

let metrics = PrometheusMetricsStore::new();

// Registrar conexão
metrics.record_connection("backend-1");

// Registrar bytes
metrics.record_bytes_sent("backend-1", 1024);
metrics.record_bytes_received("backend-1", 2048);

// Exportar formato Prometheus
let output = metrics.export_prometheus();

Métricas Expostas​

MétricaTipoDescrição
edgeproxy_connections_totalCounterTotal de conexões
edgeproxy_connections_activeGaugeConexões ativas
edgeproxy_bytes_sent_totalCounterTotal de bytes enviados
edgeproxy_bytes_received_totalCounterTotal de bytes recebidos
edgeproxy_backend_connections_totalCounterConexões por backend
edgeproxy_backend_connections_activeGaugeConexões ativas por backend
edgeproxy_backend_errors_totalCounterErros por backend
edgeproxy_backend_rtt_secondsHistogramRTT por backend

Configuração​

VariávelPadrãoDescrição
EDGEPROXY_METRICS_ENABLEDfalseHabilitar métricas Prometheus
EDGEPROXY_METRICS_LISTEN_ADDR0.0.0.0:9090Endereço do endpoint de métricas
EDGEPROXY_METRICS_PATH/metricsPath do endpoint de métricas

Config de Scrape Prometheus​

scrape_configs:
- job_name: 'edgeproxy'
static_configs:
- targets: ['edgeproxy:9090']
metrics_path: '/metrics'

Hot Reload de Configuração​

Monitora arquivos de configuração por mudanças e recarrega sem reiniciar.

use edgeproxy::infrastructure::{ConfigWatcher, ConfigChange};

let watcher = ConfigWatcher::new(Duration::from_secs(5));

// Monitorar um arquivo de configuração
watcher.watch_file("/etc/edgeproxy/config.toml").await?;

// Se inscrever para mudanças
let mut rx = watcher.subscribe();

// Reagir a mudanças
tokio::spawn(async move {
while let Ok(change) = rx.recv().await {
match change {
ConfigChange::FileModified(path) => {
println!("Arquivo de config alterado: {:?}", path);
// Recarregar configuração
}
ConfigChange::ValueChanged { key, new_value, .. } => {
println!("Config {} alterada para {}", key, new_value);
}
ConfigChange::FullReload => {
println!("Reload completo de config");
}
}
}
});

Configuração​

VariávelPadrãoDescrição
EDGEPROXY_CONFIG_WATCH_ENABLEDfalseHabilitar monitoramento de arquivo de config
EDGEPROXY_CONFIG_WATCH_INTERVAL_SECS5Intervalo de verificação de arquivo

Configurações Recarregáveis​

O seguinte pode ser alterado sem reiniciar:

  • Pesos e limites de backends
  • Parâmetros de health check
  • Thresholds de rate limit
  • Configurações de circuit breaker

Repositório PostgreSQL de Backends​

Armazenamento de backends pronto para produção usando PostgreSQL.

use edgeproxy::adapters::outbound::{PostgresBackendRepository, PostgresConfig};

let repo = PostgresBackendRepository::new(PostgresConfig {
url: "postgres://user:pass@localhost:5432/edgeproxy".to_string(),
max_connections: 10,
min_connections: 2,
connect_timeout: Duration::from_secs(5),
query_timeout: Duration::from_secs(10),
reload_interval: Duration::from_secs(5),
});

// Inicializar (cria tabelas se necessário)
repo.initialize().await?;

// Iniciar sync em background
repo.start_sync();

// Usar como trait BackendRepository
let backends = repo.get_healthy().await;

Configuração​

VariávelPadrãoDescrição
EDGEPROXY_POSTGRES_ENABLEDfalseUsar PostgreSQL para backends
EDGEPROXY_POSTGRES_URL(obrigatório)URL de conexão PostgreSQL
EDGEPROXY_POSTGRES_MAX_CONNECTIONS10Máximo de conexões no pool
EDGEPROXY_POSTGRES_MIN_CONNECTIONS2Mínimo de conexões no pool
EDGEPROXY_POSTGRES_CONNECT_TIMEOUT_SECS5Timeout de conexão
EDGEPROXY_POSTGRES_QUERY_TIMEOUT_SECS10Timeout de query
EDGEPROXY_POSTGRES_RELOAD_SECS5Intervalo de reload do cache

Schema​

CREATE TABLE backends (
id TEXT PRIMARY KEY,
app TEXT NOT NULL,
region TEXT NOT NULL,
country TEXT NOT NULL,
wg_ip TEXT NOT NULL,
port INTEGER NOT NULL,
healthy INTEGER NOT NULL DEFAULT 1,
weight INTEGER NOT NULL DEFAULT 1,
soft_limit INTEGER NOT NULL DEFAULT 100,
hard_limit INTEGER NOT NULL DEFAULT 150,
deleted INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_backends_healthy ON backends(healthy) WHERE deleted = 0;
CREATE INDEX idx_backends_region ON backends(region) WHERE deleted = 0;

Exemplo de Configuração de Produção​

Exemplo completo com todos os componentes de infraestrutura habilitados:

# Core
export EDGEPROXY_LISTEN_ADDR="0.0.0.0:8080"
export EDGEPROXY_REGION="sa"

# PostgreSQL Backend
export EDGEPROXY_POSTGRES_ENABLED=true
export EDGEPROXY_POSTGRES_URL="postgres://edgeproxy:secret@postgres:5432/edgeproxy"

# TLS
export EDGEPROXY_TLS_ENABLED=true
export EDGEPROXY_TLS_LISTEN_ADDR="0.0.0.0:8443"
export EDGEPROXY_TLS_CERT="/etc/ssl/edgeproxy.crt"
export EDGEPROXY_TLS_KEY="/etc/ssl/edgeproxy.key"

# API
export EDGEPROXY_API_ENABLED=true
export EDGEPROXY_API_LISTEN_ADDR="0.0.0.0:8081"

# Rate Limiting
export EDGEPROXY_RATE_LIMIT_ENABLED=true
export EDGEPROXY_RATE_LIMIT_MAX_REQUESTS=1000
export EDGEPROXY_RATE_LIMIT_BURST=50

# Circuit Breaker
export EDGEPROXY_CIRCUIT_BREAKER_ENABLED=true
export EDGEPROXY_CIRCUIT_FAILURE_THRESHOLD=5
export EDGEPROXY_CIRCUIT_TIMEOUT_SECS=30

# Health Checks
export EDGEPROXY_HEALTH_CHECK_ENABLED=true
export EDGEPROXY_HEALTH_CHECK_TYPE=http
export EDGEPROXY_HEALTH_CHECK_PATH=/health

# Connection Pooling
export EDGEPROXY_POOL_ENABLED=true
export EDGEPROXY_POOL_MAX_PER_BACKEND=20

# Prometheus Metrics
export EDGEPROXY_METRICS_ENABLED=true
export EDGEPROXY_METRICS_LISTEN_ADDR="0.0.0.0:9090"

# Graceful Shutdown
export EDGEPROXY_SHUTDOWN_TIMEOUT_SECS=60

./edge-proxy