HeliosProxy Integration Guide
HeliosProxy Integration Guide
How to integrate HeliosProxy into your application stack.
Quick Start
1. Build HeliosProxy
# Minimal buildcargo build --release -p heliosdb-proxy
# With connection pooling modescargo build --release -p heliosdb-proxy --features pool-modes
# Full feature buildcargo build --release -p heliosdb-proxy --features pool-modes,distribcache2. Create Configuration
listen_address = "127.0.0.1:5433"admin_address = "127.0.0.1:9090"
[pool_mode]mode = "transaction"max_pool_size = 100
[load_balancer]read_write_split = trueread_strategy = "least_connections"
[[nodes]]host = "127.0.0.1"port = 5432role = "primary"3. Start the Proxy
heliosdb-proxy --config /etc/heliosproxy/config.toml4. Connect Applications
# Connect via proxy instead of directly to databasepsql -h localhost -p 5433 -U myuser -d mydbApplication Integration
Python (psycopg2/asyncpg)
# Before: Direct connectionconn = psycopg2.connect( host="db.example.com", port=5432, database="mydb")
# After: Via HeliosProxyconn = psycopg2.connect( host="proxy.example.com", port=5433, # Proxy port database="mydb")Node.js (pg)
// Before: Direct connectionconst pool = new Pool({ host: 'db.example.com', port: 5432, database: 'mydb'});
// After: Via HeliosProxyconst pool = new Pool({ host: 'proxy.example.com', port: 5433, // Proxy port database: 'mydb'});Java (JDBC)
// BeforeString url = "jdbc:postgresql://db.example.com:5432/mydb";
// AfterString url = "jdbc:postgresql://proxy.example.com:5433/mydb";Go (pgx)
// Beforeconn, err := pgx.Connect(ctx, "postgres://user:pass@db.example.com:5432/mydb")
// Afterconn, err := pgx.Connect(ctx, "postgres://user:pass@proxy.example.com:5433/mydb")Rust (tokio-postgres)
// Beforelet (client, connection) = tokio_postgres::connect( "host=db.example.com port=5432 dbname=mydb", NoTls).await?;
// Afterlet (client, connection) = tokio_postgres::connect( "host=proxy.example.com port=5433 dbname=mydb", NoTls).await?;Connection Pooling Best Practices
Choosing a Pool Mode
| Use Case | Recommended Mode | Reason |
|---|---|---|
| Web applications | transaction | Connections returned after each request |
| Microservices | transaction | Efficient sharing between services |
| Background jobs | session | Long-running operations |
| Prepared statements | session | Statements tied to connection |
| Simple SELECT queries | statement | Maximum connection efficiency |
Transaction Mode Guidelines
When using mode = "transaction":
# Good: Transaction boundaries are clearwith conn.cursor() as cur: cur.execute("BEGIN") cur.execute("INSERT INTO orders VALUES (%s)", (order_id,)) cur.execute("COMMIT") # Connection returned to pool here
# Bad: Implicit transaction holds connectionwith conn.cursor() as cur: cur.execute("SELECT * FROM orders") # Process results slowly... # Connection held until next statement or disconnectStatement Mode Guidelines
When using mode = "statement":
# Good: Simple, independent queriesresults = []for id in ids: cur.execute("SELECT * FROM items WHERE id = %s", (id,)) results.append(cur.fetchone())
# Bad: Prepared statements won't workcur.execute("PREPARE get_item AS SELECT * FROM items WHERE id = $1")cur.execute("EXECUTE get_item(1)") # May fail - different connectionQuery Routing with Hints
Use SQL comments to control routing:
-- Force to primary (for critical reads)SELECT /* helios:route=primary */ balance FROM accounts WHERE id = 1;
-- Force to standby (for read replicas)SELECT /* helios:route=standby */ * FROM analytics_data;
-- Skip cache (for real-time data)SELECT /* helios:cache=skip */ * FROM live_metrics;
-- Multiple hintsSELECT /* helios:route=standby helios:cache=skip */ * FROM events;Application Helper
def read_from_primary(query): """Execute query on primary node.""" return f"/* helios:route=primary */ {query}"
def read_from_replica(query): """Execute query on replica node.""" return f"/* helios:route=standby */ {query}"
# Usagecur.execute(read_from_primary("SELECT balance FROM accounts WHERE id = %s"), (user_id,))High Availability Setup
Multi-Node Configuration
listen_address = "0.0.0.0:5433"admin_address = "0.0.0.0:9090"
[pool_mode]mode = "transaction"max_pool_size = 50
[load_balancer]read_write_split = trueread_strategy = "least_connections"
[health]check_interval_secs = 5failure_threshold = 3
# Primary node[[nodes]]host = "db-primary.internal"port = 5432role = "primary"
# Sync standby for failover[[nodes]]host = "db-standby.internal"port = 5432role = "standby"
# Read replicas for scaling[[nodes]]host = "db-replica-1.internal"port = 5432role = "replica"weight = 100
[[nodes]]host = "db-replica-2.internal"port = 5432role = "replica"weight = 100Failover Behavior
- Primary fails: Writes queue until
write_timeout_secsor new primary elected - Standby promoted: Proxy detects new primary via health checks
- Replica fails: Traffic redistributed to remaining replicas
- All replicas fail: Reads fall back to primary
Kubernetes Deployment
ConfigMap
apiVersion: v1kind: ConfigMapmetadata: name: heliosproxy-configdata: config.toml: | listen_address = "0.0.0.0:5433" admin_address = "0.0.0.0:9090"
[pool_mode] mode = "transaction" max_pool_size = 100
[[nodes]] host = "heliosdb-primary.default.svc.cluster.local" port = 5432 role = "primary"
[[nodes]] host = "heliosdb-standby.default.svc.cluster.local" port = 5432 role = "standby"Deployment
apiVersion: apps/v1kind: Deploymentmetadata: name: heliosproxyspec: replicas: 2 selector: matchLabels: app: heliosproxy template: metadata: labels: app: heliosproxy spec: containers: - name: heliosproxy image: heliosdb/proxy:v1.0.0 ports: - containerPort: 5433 name: postgres - containerPort: 9090 name: admin volumeMounts: - name: config mountPath: /etc/heliosproxy livenessProbe: httpGet: path: /health port: admin initialDelaySeconds: 5 readinessProbe: httpGet: path: /health port: admin initialDelaySeconds: 2 volumes: - name: config configMap: name: heliosproxy-configService
apiVersion: v1kind: Servicemetadata: name: heliosproxyspec: selector: app: heliosproxy ports: - name: postgres port: 5433 targetPort: 5433 - name: admin port: 9090 targetPort: 9090Docker Compose
version: '3.8'
services: heliosproxy: image: heliosdb/proxy:v1.0.0 ports: - "5433:5433" - "9090:9090" volumes: - ./config.toml:/etc/heliosproxy/config.toml:ro depends_on: - heliosdb-primary - heliosdb-standby healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9090/health"] interval: 5s timeout: 3s retries: 3
heliosdb-primary: image: heliosdb/heliosdb-lite:latest ports: - "5432:5432" environment: - HELIOS_ROLE=primary
heliosdb-standby: image: heliosdb/heliosdb-lite:latest environment: - HELIOS_ROLE=standby - HELIOS_PRIMARY_HOST=heliosdb-primaryMonitoring
Prometheus Metrics
HeliosProxy exposes metrics at /metrics:
# Connection pool metricsheliosproxy_pool_connections_total{node="primary"} 50heliosproxy_pool_connections_active{node="primary"} 12heliosproxy_pool_connections_idle{node="primary"} 38heliosproxy_pool_acquire_duration_seconds_bucket{le="0.001"} 9500heliosproxy_pool_acquire_duration_seconds_bucket{le="0.01"} 9900heliosproxy_pool_acquire_duration_seconds_bucket{le="0.1"} 10000
# Query metricsheliosproxy_queries_total{type="read"} 150000heliosproxy_queries_total{type="write"} 25000heliosproxy_query_duration_seconds_bucket{le="0.001"} 100000heliosproxy_query_duration_seconds_bucket{le="0.01"} 145000
# Health metricsheliosproxy_node_healthy{node="primary"} 1heliosproxy_node_healthy{node="standby"} 1heliosproxy_node_latency_seconds{node="primary"} 0.0005Grafana Dashboard
Import the HeliosProxy dashboard from docs/monitoring/grafana-dashboard.json.
Troubleshooting
Connection Issues
# Check proxy healthcurl http://localhost:9090/health
# Check pool statscurl http://localhost:9090/pool/stats
# Check node statuscurl http://localhost:9090/nodesPool Exhaustion
Symptoms: connection acquire timeout errors
Solutions:
- Increase
max_pool_size - Switch to
transactionorstatementmode - Reduce application connection hold time
- Scale horizontally with multiple proxy instances
Query Routing Issues
# Enable debug loggingRUST_LOG=heliosdb_proxy=debug heliosdb-proxy --config config.toml
# Check routing decisions in logs# [DEBUG] Routing query to node=primary reason=write_query# [DEBUG] Routing query to node=replica-1 reason=read_query