SGShardedCluster: the SGPostgresConfig referenced by a query router override is ignored and the workers one is used instead
Summary
In an SGShardedCluster using the citus sharding technology, an entry of
spec.workers.overrides[] with type: queryRouter is only partially applied:
- the fields that end up directly in the generated
SGClusterspec (sgInstanceProfile,pods,scheduling,configurations.sgPoolingConfig, ...) are honoured; configurations.sgPostgresConfigis ignored: the per query routerSGPostgresConfiggenerated by the operator is derived fromspec.workers.configurations.sgPostgresConfig.
Deleting the generated SGPostgresConfig makes the operator regenerate it, still as a copy
of the workers one, which confirms that the wrong source is used when the resource is built,
not that the resource is stale.
Root cause
There are two override lookups for query routers, using two different index conventions:
StackGresShardedClusterSpec.getQueryRoutersOverrides()filters the overrides bytype: queryRouterand shifts their index byspec.coordinator.queryRouterIndexOffset(default1024). It is used byStackGresShardedClusterForUtil.getBaseQueryRouterCluster(), which is why every field that is copied into the generatedSGClusterspec works as expected.StackGresShardedClusterSpec.getPlainOverrides()does not filter by type and does not apply the offset. It is used byShardedClusterWorkersClustersContextAppender.getQueryRoutersClusters(), which then matches the overrides against the global query router index (queryRouterIndexOffset + i). No override can ever match, soShardedClusterWorkersPostgresConfigContextAppender.findPostgresConfig()falls back tospec.workers.configurations.sgPostgresConfig, andCitusShardedClusterQueryRouterPostgresConfigmaterializes that fallback as the per query routerSGPostgresConfig.
The same broken lookup also feeds the resolved SGPoolingConfig and SGInstanceProfile of
the query routers in the reconciliation context. Those are not visibly broken because the
generated SGCluster spec carries the referenced names directly, but the context values are
wrong, which affects validation and anything else relying on them.
Related defect
Since getPlainOverrides() neither filters by type nor applies the offset, an override with
type: queryRouter and index N is also returned with index N and is therefore matched
as the override of worker N by
ShardedClusterWorkersClustersContextAppender.getWorkersClusters(). A query router override
can then leak into the SGPostgresConfig, SGPoolingConfig and SGInstanceProfile resolved
for the worker with the same index. To be confirmed with a test.
Expected behaviour and design decision
Beyond fixing the lookup, we should decide what the default Postgres configuration of a query router is when no override is provided. Query routers do not run the same workload as the workers, and inheriting the workers configuration (or the coordinator one) is arguably not a good default for either choice. Options:
- Minimum fix: honour
overrides[].configurations.sgPostgresConfigfor entries withtype: queryRouter. - Add a dedicated section for query routers (e.g. under
spec.coordinator) holding their ownconfigurations, used as the default for all query routers, so that a user does not need to declare one override per query router just to change their Postgres configuration.
Actionables
- Use
getQueryRoutersOverrides()(or an index aware equivalent) inShardedClusterWorkersClustersContextAppender.getQueryRoutersClusters(). - Make the worker lookup type aware so that a query router override can not be matched
as a worker override (either by filtering in
getPlainOverrides()or by replacing it withgetWorkersOverrides()plusgetQueryRoutersOverrides()). - Decide and implement the default source of the query routers configurations, and
apply the same decision to
sgPoolingConfigandsgInstanceProfile. - Add unit tests in
ShardedClusterWorkersPostgresConfigContextAppenderTest,ShardedClusterWorkersPoolingConfigContextAppenderTestandShardedClusterWorkersInstanceProfileContextAppenderTestcovering a query router override and the index collision with the worker of the same plain index. - Add a test on
CitusShardedClusterQueryRouterPostgresConfigasserting the generatedSGPostgresConfigcomes from the overriddenSGPostgresConfig. - Extend the citus sharded cluster e2e spec with a query router override that references
its own
SGPostgresConfig. - State, in the
SGShardedClusterCRD field descriptions and in the sharded cluster administration guide, that theindexof an override of typequeryRouteris 0 based within the query routers, and what the default configurations of a query router are.