-
Notifications
You must be signed in to change notification settings - Fork 58
Expand file tree
/
Copy path.env.example
More file actions
384 lines (309 loc) · 15 KB
/
Copy path.env.example
File metadata and controls
384 lines (309 loc) · 15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
# =============================================================================
# Trident — environment variable reference
# =============================================================================
# Copy this file to .env and fill in real values before running locally.
# Never commit .env — it is git-ignored.
#
# Format: SERVICE REQUIRED/OPTIONAL description
# =============================================================================
# -----------------------------------------------------------------------------
# Shared — used by multiple services
# -----------------------------------------------------------------------------
# REQUIRED indexer + grpc-api + go-api
# Connection string for PostgreSQL.
#
# Local development: point straight at Postgres (docker-compose.dev.yml exposes
# it on localhost:5432).
#
# Production: connect through PgBouncer, NOT Postgres directly. The production
# compose (docker/docker-compose.yml) already rewrites this to
# postgres://<user>:<pass>@pgbouncer:6432/<db>
# for each service. On Fly.io use the pooler connection string (the Fly Postgres
# proxy port 5432), not the direct port 5433 — see docs/deployment.md.
DATABASE_URL=postgresql://trident:password@localhost:5432/trident
# REQUIRED indexer + go-api
# Connection string for Redis. The indexer publishes events here; the Go API
# consumes them for WebSocket fan-out.
REDIS_URL=redis://localhost:6379
# ---------------------------------------------------------------------------
# Database connection pool sizing (issue #87)
#
# Each value is the pool size for ONE instance of that service. The total number
# of concurrent connections a service tier opens against PgBouncer is
# pool_size * number_of_replicas
# PgBouncer's PGBOUNCER_DEFAULT_POOL_SIZE must be >= the sum across all tiers.
# ---------------------------------------------------------------------------
# OPTIONAL indexer default: 3
# Indexer: single writer, low concurrency — a small pool is correct.
INDEXER_DB_POOL_SIZE=3
# OPTIONAL grpc-api default: 10
# Rust gRPC API: read-heavy, moderate concurrency.
GRPC_API_DB_POOL_SIZE=10
# OPTIONAL go-api default: 5
# Go REST API: per-replica pool. With 3 replicas this is 15 connections total
# against PgBouncer.
GO_API_DB_POOL_SIZE=5
# OPTIONAL go-api default: 0
# Minimum pool connections kept open (issue #238). 0 matches pgxpool's own
# default — raise it to pre-warm connections and cut cold-start latency.
GO_API_DB_POOL_MIN_CONNS=0
# OPTIONAL go-api default: 1800000 (30 min)
# Maximum age of a pooled connection before it's recycled (issue #238). A
# random jitter of 10% of this value is applied automatically so connections
# don't all recycle at once.
GO_API_DB_POOL_MAX_CONN_LIFETIME_MS=1800000
# OPTIONAL go-api default: 300000 (5 min)
# How long an idle pooled connection is kept before it's closed (issue #238).
GO_API_DB_POOL_MAX_CONN_IDLE_TIME_MS=300000
# OPTIONAL go-api default: 60000 (1 min)
# How often idle pooled connections are health-checked (issue #238).
GO_API_DB_POOL_HEALTH_CHECK_PERIOD_MS=60000
# OPTIONAL go-api
# PgBouncer admin console connection, used by GET /v1/admin/db to read
# SHOW POOLS / SHOW STATS. Connect to the virtual "pgbouncer" database.
PGBOUNCER_ADMIN_URL=postgres://trident:password@localhost:6432/pgbouncer
# OPTIONAL go-api
# Shared secret required (via the X-Admin-Key header) to call /v1/admin/*.
# Leave empty to disable the admin endpoints. Generate with: openssl rand -hex 32
ADMIN_API_KEY=
# OPTIONAL go-api
# Comma-separated HMAC-SHA256 hashes of accepted API keys, using API_KEY_SALT.
API_KEY_HASHES=
# -----------------------------------------------------------------------------
# Rust indexer (crates/indexer)
# -----------------------------------------------------------------------------
# REQUIRED indexer
# Soroban RPC endpoint. For testnet: https://soroban-testnet.stellar.org
# For mainnet use a private node or https://horizon.stellar.org/soroban/rpc
STELLAR_RPC_URL=https://soroban-testnet.stellar.org
# OPTIONAL indexer default: testnet
# Network identifier used for contract-filter scoping.
# One of: mainnet | testnet | futurenet
NETWORK=testnet
# OPTIONAL indexer default: 1000 min: 100 max: 60000
# How often (ms) the indexer polls the RPC node between full pagination runs.
# Lower values reduce indexing latency; higher values reduce RPC load.
POLL_INTERVAL_MS=1000
# --- Adaptive poll interval (issue #198) ---
# The indexer polls fast while far behind the chain tip and backs off once
# caught up, interpolating between the floor and ceiling by chain-tip lag.
# OPTIONAL indexer default: 250 min: 50 max: 60000
# Shortest poll interval (ms), used when lag >= LAG_HIGH_WATERMARK.
POLL_INTERVAL_FLOOR_MS=250
# OPTIONAL indexer default: 5000 min: 100 max: 600000
# Longest poll interval (ms), used when the indexer is caught up (lag 0).
# Must be greater than POLL_INTERVAL_FLOOR_MS.
POLL_INTERVAL_CEILING_MS=5000
# OPTIONAL indexer default: 100 min: 1 max: 100000000
# Chain-tip lag (ledgers) at or above which the floor interval applies.
LAG_HIGH_WATERMARK=100
# OPTIONAL indexer default: 10 min: 0 max: 1000000
# Hysteresis deadband (ledgers): lag must move at least this much to change the
# interval, preventing oscillation around a threshold.
POLL_HYSTERESIS_LEDGERS=10
# OPTIONAL indexer default: 200 min: 1 max: 10000
# Maximum events fetched from the RPC per getEvents request (page size).
# Reducing this lowers peak memory; increasing it speeds up backfill.
MAX_EVENTS_PER_POLL=200
# OPTIONAL indexer default: 1000 min: 1 max: 10000
# Maximum rows per batched INSERT when a page is committed. A page is written in
# one transaction; this only caps how many rows go into each statement, so a very
# large catch-up page cannot build an unbounded statement.
DB_BATCH_SIZE=1000
# OPTIONAL indexer default: none (no topic narrowing)
# Topic patterns pushed into the getEvents RPC filter alongside the contract
# allowlist, so the RPC stops sending events that would be discarded anyway.
# Comma-separated patterns; segments separated by "/"; "*" matches one topic
# position and "**" matches the remainder. Segment count must match the events
# you want, so include a wildcard per trailing topic:
# INDEX_TOPIC_FILTERS=transfer/*/*,mint/*/*
# Only applied when the indexed_contracts allowlist is non-empty — an empty
# allowlist always means index-all. An invalid pattern fails startup.
# INDEX_TOPIC_FILTERS=
# OPTIONAL indexer default: 10000
# Maximum number of events kept in the Redis stream before trimming.
# Reduces memory on the broker; lower values risk missing events on slow consumers.
REDIS_STREAM_MAXLEN=10000
# OPTIONAL indexer default: false
# Set to true to store Soroban diagnostic events (emitted only in debug mode).
# Leave false for production — diagnostic events are high-volume.
INDEX_DIAGNOSTIC=false
# OPTIONAL indexer default: 9090
# Port the indexer serves its Prometheus /metrics endpoint on. Not authenticated —
# firewall it at the network level rather than exposing it publicly.
METRICS_PORT=9090
# OPTIONAL indexer default: info
# Log verbosity. One of: error | warn | info | debug | trace
RUST_LOG=info
# OPTIONAL indexer default: 8080
# Port serving /healthz and /readyz.
HEALTH_PORT=8080
# OPTIONAL indexer + go-api default: 30000 / 10000
# Postgres per-statement and idle-in-transaction timeout bounds (ms), applied
# to every connection at connect time. Shared across both services (issue
# #238) so they agree on how long a query or idle transaction may hold a
# connection; bounded to [100, 3600000]ms, out-of-range values are clamped.
DB_STATEMENT_TIMEOUT_MS=30000
DB_IDLE_IN_TRANSACTION_TIMEOUT_MS=10000
# OPTIONAL indexer default: 86400
# How often (seconds) cached token metadata is refreshed.
TOKEN_METADATA_REFRESH_INTERVAL_SECS=86400
# OPTIONAL indexer default: unset (disabled)
# Enables tokio-console diagnostics. Only takes effect when the binary is
# built with the tokio-console cargo feature.
TOKIO_CONSOLE_ENABLED=false
# OPTIONAL indexer required for non-standard networks
# Stellar network passphrase, used to derive SAC contract ids for
# TRACKED_SAC_ASSETS. Inferred automatically for NETWORK=testnet/mainnet/pubnet.
NETWORK_PASSPHRASE=
# OPTIONAL indexer default: none
# Assets (e.g. "USDC:GA...") to derive Stellar Asset Contract ids for and track.
TRACKED_SAC_ASSETS=
# --- RPC transport and failover ---
# OPTIONAL indexer default: 5000 / 30000 / 90000 / 8 / 60000
RPC_CONNECT_TIMEOUT_MS=5000
RPC_REQUEST_TIMEOUT_MS=30000
RPC_POOL_IDLE_TIMEOUT_MS=90000
RPC_POOL_MAX_IDLE_PER_HOST=8
RPC_TCP_KEEPALIVE_MS=60000
# OPTIONAL indexer default: 3 / 30000
# Consecutive failures before an RPC endpoint is parked, and how long it
# waits before being retried.
RPC_FAILOVER_THRESHOLD=3
RPC_ENDPOINT_COOLDOWN_MS=30000
# --- Outbox relay ---
# OPTIONAL indexer default: 100 / 500 / 10000
OUTBOX_POLL_INTERVAL_MS=100
OUTBOX_BATCH_SIZE=500
OUTBOX_BACKLOG_ALERT_THRESHOLD=10000
# --- Lag alerting ---
# OPTIONAL indexer default: empty (disabled)
# Outbound webhook URL for indexer lag/recovery alerts.
ALERT_WEBHOOK_URL=
# OPTIONAL indexer default: 200 / 30
ALERT_LAG_THRESHOLD=200
ALERT_COOLDOWN_MINUTES=30
# -----------------------------------------------------------------------------
# Rust gRPC API (crates/api)
# -----------------------------------------------------------------------------
# REQUIRED grpc-api
# Already listed above: DATABASE_URL
# REQUIRED grpc-api
# Address the gRPC server binds to.
GRPC_ADDR=0.0.0.0:50051
# OPTIONAL grpc-api default: 128
# In-flight event buffer per StreamEvents subscriber. When it fills, the Redis
# consumer for that subscriber blocks — that backpressure is deliberate, and is
# what stops a slow client from making the server queue events without limit.
# Raise it for bursty clients; lower it to cap per-subscriber memory.
STREAM_CHANNEL_BUFFER=128
# -----------------------------------------------------------------------------
# Go REST API (services/api)
# -----------------------------------------------------------------------------
# REQUIRED go-api
# Already listed above: DATABASE_URL, REDIS_URL
# REQUIRED go-api
# Address of the upstream Rust gRPC API that the Go layer calls for data.
API_GRPC_ADDR=localhost:50051
# OPTIONAL go-api default: 3000
# Port the Go HTTP server listens on.
PORT=3000
# OPTIONAL go-api
# Random secret used to salt API key hashes. Change before deployment.
# Generate with: openssl rand -hex 32
API_KEY_SALT=change-this-to-a-random-string
# REQUIRED in production go-api
# Comma-separated CORS allow-list (https:// origins, or http://localhost*).
# Dev mode allows any origin when unset — never leave unset in production.
ALLOWED_ORIGINS=http://localhost:3000
# OPTIONAL go-api default: 30000
# Per-request timeout (ms). Does not apply to /ws or /v1/events/stream.
REQUEST_TIMEOUT_MS=30000
# OPTIONAL go-api default: 1000
# Max concurrent WebSocket connections before new ones are rejected.
MAX_WS_CONNECTIONS=1000
# OPTIONAL grpc-api + go-api default: trident:events
# Redis stream key used for event pub/sub and webhook consumption. Must match
# between the indexer (publisher) and the Go API (consumer).
REDIS_STREAM_KEY=trident:events
# OPTIONAL go-api default: trident-webhooks / webhook-worker
# Redis Stream consumer group/name for the webhook delivery worker.
WEBHOOK_CONSUMER_GROUP=trident-webhooks
WEBHOOK_CONSUMER_NAME=webhook-worker
# OPTIONAL go-api defaults: 10 / 100 / 1000
# Requests/sec limits per API key tier.
RATE_LIMIT_FREE_RPS=10
RATE_LIMIT_PRO_RPS=100
RATE_LIMIT_INTERNAL_RPS=1000
# OPTIONAL go-api defaults: 90 / 30 / 30 / 0 (0 = disabled)
# Days to retain each table's rows before pruning.
RETENTION_AUDIT_LOG_DAYS=90
RETENTION_PARSE_ERRORS_DAYS=30
RETENTION_WEBHOOK_DELIVERIES_DAYS=30
RETENTION_SOROBAN_EVENTS_DAYS=0
# OPTIONAL go-api default: false / 127.0.0.1:6060
# Internal-only pprof profiling server. Never expose this publicly — bind
# only to loopback, and keep it disabled in production unless actively
# debugging.
PPROF_ENABLED=false
PPROF_ADDR=127.0.0.1:6060
# OPTIONAL go-api default: 9091
# Port the Go REST API serves its Prometheus /metrics endpoint on (issue #58),
# separate from the public API port. This is a distinct process/port from the
# Rust indexer's own METRICS_PORT (default 9090) documented above — same env
# var name, different service.
METRICS_PORT=9091
# ---------------------------------------------------------------------------
# Internal /internal/status auth (issue #316)
# ---------------------------------------------------------------------------
# REQUIRED to use GET /internal/status go-api
# Shared secret required via the X-Internal-Key header. Compared with
# crypto/subtle.ConstantTimeCompare. Leaving this unset does NOT disable
# auth — it fails closed and rejects every request to /internal/status.
# Generate with: openssl rand -hex 32
INTERNAL_API_KEY=
# ---------------------------------------------------------------------------
# Internal gRPC mTLS (issue #320) — behind a flag, off by default.
# See docs/kubernetes.md#internal-mtls for cert generation and rotation.
# ---------------------------------------------------------------------------
# OPTIONAL grpc-api + go-api default: false
# Enables mutual TLS on the internal Go API <-> Rust gRPC API hop. When
# false (default), that hop is plaintext within the cluster network (which is
# not externally reachable — see docs/kubernetes.md).
GRPC_MTLS_ENABLED=false
# REQUIRED if GRPC_MTLS_ENABLED=true grpc-api + go-api
# Path to the CA bundle used to verify the peer's certificate.
GRPC_MTLS_CA_CERT=
# REQUIRED if GRPC_MTLS_ENABLED=true grpc-api
# Paths to the gRPC server's own TLS certificate/key.
GRPC_MTLS_SERVER_CERT=
GRPC_MTLS_SERVER_KEY=
# REQUIRED if GRPC_MTLS_ENABLED=true go-api
# Paths to the Go API's client TLS certificate/key.
GRPC_MTLS_CLIENT_CERT=
GRPC_MTLS_CLIENT_KEY=
# -----------------------------------------------------------------------------
# Docker Compose (docker/docker-compose.yml)
# -----------------------------------------------------------------------------
# OPTIONAL docker-compose only
# PostgreSQL superuser credentials used when the container is first created.
POSTGRES_USER=trident
POSTGRES_PASSWORD=password
POSTGRES_DB=trident
# Environment variables for integration tests.
TEST_DATABASE_URL=postgresql://trident:password@localhost:5432/trident
TEST_REDIS_URL=redis://localhost:6379
# -----------------------------------------------------------------------------
# OpenTelemetry distributed tracing (issue #81)
# Applies to: indexer, grpc-api, go-api
# -----------------------------------------------------------------------------
# OPTIONAL all services
# OTLP gRPC endpoint for the trace collector (Jaeger, Grafana Tempo, etc.).
# Leave empty to disable tracing entirely with zero overhead.
# Local dev with docker-compose.dev.yml: http://localhost:4317
# Production (Fly.io + Grafana Tempo): set via fly secrets
OTEL_EXPORTER_OTLP_ENDPOINT=
# OPTIONAL all services default: 0.1 (10%)
# Fraction of traces to sample. 1.0 = 100% (useful in development).
# Reduce in production if trace volume is too high.
OTEL_SAMPLING_RATIO=1.0