Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
819410b
fix: set explicit timeout for big segment revisions poll to avoid cli…
LD-Sfalzon Mar 5, 2026
2d4ceb8
drop timeout period
keelerm84 Mar 5, 2026
f6a7f7e
Merge origin/v8 into feature/autoconfig-cache-init-from-store
LD-Sfalzon Mar 15, 2026
ad86ae2
feat: AutoConfig cache with initFromStoreFirst for Redis/DynamoDB
LD-Sfalzon Mar 16, 2026
bebbf96
fix: seed StreamManager from cache so first PUT applies updates and d…
LD-Sfalzon Mar 16, 2026
f0833ab
fix: AutoConfig cache cleanup and validation
LD-Sfalzon Mar 16, 2026
25679e1
fix: apply Redis TLS config in AutoConfig cache store
LD-Sfalzon Mar 16, 2026
ce95e31
refactor: rework AutoConfig cache to per-item storage
keelerm84 Mar 31, 2026
42cc63c
Merge branch 'v8' into feature/autoconfig-cache-init-from-store
keelerm84 Apr 1, 2026
87469ec
go fmt
keelerm84 Apr 1, 2026
ab85c75
refactor: internalize cache into StreamManager with noop null object
keelerm84 Apr 1, 2026
47f3ea9
simplify: accept any string as cache encryption key
keelerm84 Apr 1, 2026
4f7cf4d
simplify: use cacheKey directly without ld:autoconfig prefix
keelerm84 Apr 1, 2026
1bebdad
fix lint issue
keelerm84 Apr 1, 2026
3aa02c5
fix: remove Redis ping check from cache store construction
keelerm84 Apr 1, 2026
9c262b9
fix: continue DynamoDB batch writes on partial failure
keelerm84 Apr 1, 2026
e829bd2
feat: cache PATCH and DELETE events, not just PUTs
keelerm84 Apr 1, 2026
2762a87
gofmt
keelerm84 Apr 1, 2026
c900087
simplify: remove InitFromStoreFirst, CacheKey implies the feature
keelerm84 Apr 2, 2026
a7cd71f
fix: don't rewrite cache on startup by marking PutContent persistence
keelerm84 Apr 2, 2026
28ee728
feat: wrap cached items in a versioned envelope
keelerm84 Apr 2, 2026
6bab65d
feat: add cancellable context lifecycle to cache stores
keelerm84 Apr 2, 2026
92f613f
feat: race cache read against stream connection
keelerm84 Apr 2, 2026
f6ded73
gofmt
keelerm84 Apr 3, 2026
2fa74ef
lint issues
keelerm84 Apr 3, 2026
f72a2c1
address code review feedback
keelerm84 Apr 6, 2026
708622f
update cache cancel
keelerm84 Apr 6, 2026
2c5bd52
more feedback
keelerm84 Apr 6, 2026
32c54ff
fix nolint directive
keelerm84 Apr 6, 2026
ff10ebc
close on halt
keelerm84 Apr 6, 2026
975eec1
fix doc
keelerm84 Apr 6, 2026
b450cc7
allow cache to finish even if stream errs out
keelerm84 Apr 6, 2026
aa72bf4
ensure cache goroutine is cancelled
keelerm84 Apr 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ type AutoConfigConfig struct {
EnvDatastoreTableName string `conf:"ENV_DATASTORE_TABLE_NAME"`
EnvAllowedOrigin ct.OptStringList `conf:"ENV_ALLOWED_ORIGIN"`
EnvAllowedHeader ct.OptStringList `conf:"ENV_ALLOWED_HEADER"`
CacheKey string `conf:"AUTO_CONFIG_CACHE_KEY"`
CacheEncryptionKey string `conf:"AUTO_CONFIG_CACHE_ENCRYPTION_KEY"`
}

// OfflineModeConfig contains configuration parameters for the offline/file data source feature.
Expand Down
16 changes: 16 additions & 0 deletions config/config_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ var (
errRedisBadHostname = errors.New("invalid Redis hostname")
errConsulTokenAndTokenFile = errors.New("Consul token must be specified as either an inline value or a file, but not both") //nolint:staticcheck
errAutoConfWithFilters = errors.New("cannot configure filters if auto-configuration is enabled")
errCacheKeyWithoutStore = errors.New("AUTO_CONFIG_CACHE_KEY requires Redis or DynamoDB to be enabled")
errCacheKeyWithoutDynamoTable = errors.New("AUTO_CONFIG_CACHE_KEY with DynamoDB requires DYNAMODB_TABLE to be set")
errMissingProjKey = errors.New("when filters are configured, all environments must specify a 'projKey'")
errInvalidFileDataSourceMonitoringInterval = fmt.Errorf("file data source monitoring interval must be >= %s", minimumFileDataSourceMonitoringInterval)
errInvalidCredentialCleanupInterval = fmt.Errorf("expired credential cleanup interval must be >= %s", minimumCredentialCleanupInterval)
Expand Down Expand Up @@ -79,6 +81,7 @@ func ValidateConfig(c *Config, loggers ldlog.Loggers) error {
validateConfigEnvironments(&result, c)
validateConfigDatabases(&result, c, loggers)
validateConfigFilters(&result, c)
validateAutoConfigCache(&result, c)
validateOfflineMode(&result, c)
validateCredentialCleanupInterval(&result, c)
validateMaxInboundPayloadSize(&result, c)
Expand Down Expand Up @@ -191,6 +194,19 @@ func validateConfigFilters(result *ct.ValidationResult, c *Config) {
}
}

func validateAutoConfigCache(result *ct.ValidationResult, c *Config) {
if !c.AutoConfig.Key.Defined() || strings.TrimSpace(c.AutoConfig.CacheKey) == "" {
return
}
hasStore := c.Redis.URL.IsDefined() || c.DynamoDB.Enabled
if !hasStore {
result.AddError(nil, errCacheKeyWithoutStore)
}
if c.DynamoDB.Enabled && strings.TrimSpace(c.DynamoDB.TableName) == "" {
result.AddError(nil, errCacheKeyWithoutDynamoTable)
}
}

func validateOfflineMode(result *ct.ValidationResult, c *Config) {
if c.OfflineMode.FileDataSourceMonitoringInterval.IsDefined() {
interval := c.OfflineMode.FileDataSourceMonitoringInterval.GetOrElse(0)
Expand Down
20 changes: 12 additions & 8 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,20 @@ to authorize using that credential. Relay will periodically check for expired cr

This section is only applicable if [automatic configuration](https://docs.launchdarkly.com/home/advanced/relay-proxy-enterprise/automatic-configuration) is enabled for your account.

| Property in file | Environment var | Type | Default | Description |
|--------------------------|----------------------------|:------:|:--------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `key` | `AUTO_CONFIG_KEY` | String | | A valid Relay Proxy automatic configuration key. |
| `envDatastorePrefix` | `ENV_DATASTORE_PREFIX` | String | | If using a Redis, Consul, or DynamoDB store, this string will be added to all database keys to distinguish them from any other environments that are using the database. _(6)_ |
| `envDatastoreTableName ` | `ENV_DATASTORE_TABLE_NAME` | String | | If using a DynamoDB store, this specifies the table name. _(6)_ |
| `envAllowedOrigin` | `ENV_ALLOWED_ORIGIN` | URI | | If provided, adds CORS headers to prevent access from other domains. This variable can be provided multiple times per environment (if using the `ENV_ALLOWED_ORIGIN` variable, specify a comma-delimited list). |
| `envAllowedHeader` | `ENV_ALLOWED_HEADER` | String | | If provided, adds the specify headers to the list of accepted headers for CORS requests. This variable can be provided multiple times per environment (if using the `ENV_ALLOWED_HEADER` variable, specify a comma-delimited list). |
| Property in file | Environment var | Type | Default | Description |
|--------------------------|---------------------------------------|:-------:|:--------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `key` | `AUTO_CONFIG_KEY` | String | | A valid Relay Proxy automatic configuration key. |
| `cacheKey` | `AUTO_CONFIG_CACHE_KEY` | String | | Enables AutoConfig caching in the persistent store (Redis/Valkey or DynamoDB). Requires Redis or DynamoDB. Multiple Relay instances can share the same store by using different cache keys. _(7)_ |
| `cacheEncryptionKey` | `AUTO_CONFIG_CACHE_ENCRYPTION_KEY` | String | _(auto)_ | Encrypts cached AutoConfig data. Can be any string; derived to a 256-bit AES key via SHA-256. If omitted, the AutoConfig key is used. _(7)_ |
| `envDatastorePrefix` | `ENV_DATASTORE_PREFIX` | String | | If using a Redis, Consul, or DynamoDB store, this string will be added to all database keys to distinguish them from any other environments that are using the database. _(6)_ |
| `envDatastoreTableName ` | `ENV_DATASTORE_TABLE_NAME` | String | | If using a DynamoDB store, this specifies the table name. _(6)_ |
| `envAllowedOrigin` | `ENV_ALLOWED_ORIGIN` | URI | | If provided, adds CORS headers to prevent access from other domains. This variable can be provided multiple times per environment (if using the `ENV_ALLOWED_ORIGIN` variable, specify a comma-delimited list). |
| `envAllowedHeader` | `ENV_ALLOWED_HEADER` | String | | If provided, adds the specify headers to the list of accepted headers for CORS requests. This variable can be provided multiple times per environment (if using the `ENV_ALLOWED_HEADER` variable, specify a comma-delimited list). |

_(6)_ When using a database store, if there are multiple environments, it is necessary to have a different prefix for each environment (or, if using DynamoDB, a different table name). The `envDataStorePrefix` and `envDatastoreTableName` properties support this by recognizing the special symbol `$CID` as a placeholder for the environment's client-side ID. For instance, if an environment's ID is `1234567890abcdef` and you set `envDatastorePrefix` to `ld-flags-$CID`, the actual prefix used for that environment will be `ld-flags-1234567890abcdef`.

_(7)_ When `cacheKey` is set, Relay races a cache read against the LaunchDarkly stream connection at startup. If the cache returns first, Relay can serve traffic immediately while the stream connects. Stream updates are persisted to the cache as they arrive. Cached data is encrypted with `cacheEncryptionKey` (or the AutoConfig key if omitted).


### File section: `[OfflineMode]`

Expand Down Expand Up @@ -302,7 +306,7 @@ To learn more, read [Metrics integrations](./metrics.md).
| `idleConnTimeout` | `HTTP_IDLE_CONN_TIMEOUT` | Duration | | Maximum amount of time an idle (keep-alive) HTTP connection will remain idle before closing. Examples: `30s`, `5m`. If not set, uses Go's default of 90 seconds. Reducing this can help prevent EOF errors when intermediate load balancers or NAT gateways close idle connections. |
| `maxIdleConns` | `HTTP_MAX_IDLE_CONNS` | Integer | | Maximum number of idle (keep-alive) HTTP connections across all hosts. If not set, uses Go's default of 100. Increase this value for high-concurrency scenarios with many environments. |
| `maxIdleConnsPerHost` | `HTTP_MAX_IDLE_CONNS_PER_HOST` | Integer | | Maximum number of idle (keep-alive) HTTP connections to keep per-host. If not set, uses Go's default of 2. Increase this if you have multiple environments connecting to the same LaunchDarkly endpoints. |
| `disableKeepAlive` | `HTTP_DISABLE_KEEPALIVE` | Boolean | `false` | When enabled, disables HTTP keep-alive connections. This forces the relay to use a new connection for each HTTP request. Use this only for debugging connection issues, as it significantly increases overhead. |
| `disableKeepAlives` | `HTTP_DISABLE_KEEPALIVE` | Boolean | `false` | When enabled, disables HTTP keep-alive connections. This forces the relay to use a new connection for each HTTP request. Use this only for debugging connection issues, as it significantly increases overhead. |

### Experimental/testing variables

Expand Down
Loading
Loading