Skip to content

chore(router): enrich logs with execution config hashes#2942

Merged
dkorittki merged 8 commits into
mainfrom
dominik/eng-9706-log-engine-config-hashes
Jun 11, 2026
Merged

chore(router): enrich logs with execution config hashes#2942
dkorittki merged 8 commits into
mainfrom
dominik/eng-9706-log-engine-config-hashes

Conversation

@dkorittki

@dkorittki dkorittki commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

During graph server swap, enrich logs with old and new execution config hashes. Helps users identify the used router execution configs. Also fixes a bug where a failed initial fetch from CDN would result in next fetch attempts to ignore that particular engine configuration.

Summary by CodeRabbit

  • New Features

    • Responses now include per-graph execution-config hash info for finer change visibility.
  • Bug Fixes & Improvements

    • More detailed debug logging around mux selection and reuse.
    • Polling skips ignored/missing feature flags and avoids redundant rebuilds.
    • Hot-reload updates include per-graph hash transitions so changes are tracked precisely.
  • Tests

    • Expanded tests validating hash behavior, skip-missing-flag handling, and related change payloads.

Checklist

  • I have discussed my proposed changes in an issue and have received approval to proceed.
  • I have followed the coding standards of the project.
  • Tests or benchmarks have been added or updated.
  • Documentation has been updated on https://github.com/wundergraph/docs-website.
  • I have read the Contributors Guide.

Open Source AI Manifesto

This project follows the principles of the Open Source AI Manifesto. Please ensure your contribution aligns with its principles.

@github-actions github-actions Bot added the router label Jun 9, 2026
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The split-config poller now computes per-graph execution-config hashes and returns them in routerconfig.Response.Hashes. The graph server receives and uses those hashes when building/reusing base and feature-flag muxes, emitting debug logs that include per-graph old/new hash values. Tests were added/updated to validate hash behavior and skip logic.

Changes

Execution-Config Hash Tracking and Logging

Layer / File(s) Summary
Hash types and Response contract
router/pkg/routerconfig/client.go
Adds exported HashInfo{OldHash, NewHash} and Response.Hashes map[string]HashInfo to carry per-graph execution-config hashes.
Config poller: compute, filter, and propagate hashes
router/pkg/controlplane/configpoller/split_config_poller.go
Filters ignored/missing feature flags during assembly, computes per-graph hashes for initial GetRouterConfig and Subscribe, builds Changes with Old/New hash transitions, removes/adjusts hashes for skipped missing flags, recomputes composite version when needed, and includes Hashes in hot-reload routerconfig.Response.
Tests validating hash behavior
router/pkg/controlplane/configpoller/split_config_poller_test.go
Expands assertions to verify resp.Hashes contents for base-only and feature-flag configs, adds TestSplitGetRouterConfig_SkipMissingFF_NotRetainedInKnownHashesOrVersion, and validates hash transitions in Subscribe hot-reloads.
Graph server: accept and log hashes in mux logic
router/core/graph_server.go
Adds hashes to buildMultiGraphHandlerOptions, passes response.Hashes when constructing multi-graph handler, and augments debug logs for base and feature-flag mux reuse/creation to include feature-flag names and old/new execution-config hashes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • wundergraph/cosmo#2823: Both PRs modify router/core/graph_server.go’s feature-flag mux reuse/creation logic, adding/using execution-config hash data in the paths where muxes are reused or rebuilt.
  • wundergraph/cosmo#2814: Introduces split-config polling infrastructure that this PR extends with per-graph execution-config hash computation.
  • wundergraph/cosmo#2844: Also touches split-config polling and graph-server mux selection; related to per-graph hashing/versioning in that codepath.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'chore(router): enrich logs with execution config hashes' accurately describes the main change: enriching logs with execution config hashes during graph server operations.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

Router image scan passed

✅ No security vulnerabilities found in image:

ghcr.io/wundergraph/cosmo/router:sha-4fba990ad5048d799900341712e7280cb6ff9184

@codecov

codecov Bot commented Jun 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 66.33%. Comparing base (746c876) to head (2ed6642).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2942      +/-   ##
==========================================
+ Coverage   65.56%   66.33%   +0.77%     
==========================================
  Files         327      258      -69     
  Lines       46918    27539   -19379     
  Branches     5250        0    -5250     
==========================================
- Hits        30763    18269   -12494     
+ Misses      16131     7818    -8313     
- Partials       24     1452    +1428     
Files with missing lines Coverage Δ
router/core/graph_server.go 85.66% <100.00%> (ø)
...g/controlplane/configpoller/split_config_poller.go 83.15% <100.00%> (ø)
router/pkg/routerconfig/client.go 9.09% <ø> (ø)

... and 582 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
router/core/graph_server.go (2)

369-370: ⚡ Quick win

Consider defensive nil checks for response.Hashes.

Same concern as the previous comment - accessing response.Hashes[""] without nil check.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@router/core/graph_server.go` around lines 369 - 370, The log line assumes
response.Hashes and response.Hashes[""] exist; add defensive nil/exists checks
before accessing NewHash (e.g., verify response != nil, response.Hashes != nil
and that the key "" exists) in the graph server code path that contains
s.logger.With(...).Debug(...) so you only reference response.Hashes[""].NewHash
when safe and fall back to a safe placeholder or skip the field when absent.

351-354: ⚡ Quick win

Consider defensive nil checks for response.Hashes.

The code accesses response.Hashes[""] without checking if Hashes is nil. While the current splitConfigPoller implementation always initializes this map, other ConfigPoller implementations might not. Consider adding a nil check or documenting the contract that ConfigPoller.GetRouterConfig must always populate Hashes.

🛡️ Defensive coding suggestion
+	baseHash := response.Hashes[""]
+	if response.Hashes == nil {
+		baseHash = routerconfig.HashInfo{}
+	}
 	s.logger.With(
-		zap.String("old_execution_config_hash", response.Hashes[""].OldHash),
-		zap.String("new_execution_config_hash", response.Hashes[""].NewHash),
+		zap.String("old_execution_config_hash", baseHash.OldHash),
+		zap.String("new_execution_config_hash", baseHash.NewHash),
 	).Debug("Will build a new base graph mux for new graph server")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@router/core/graph_server.go` around lines 351 - 354, The log accesses
response.Hashes[""] without guarding against a nil map; add a defensive
nil-check (or zero-value fallback) before indexing response.Hashes in the graph
server code path that logs the hashes (the variables referenced as
response.Hashes[""].OldHash / NewHash) so you don't panic if a ConfigPoller
implementation returns a nil Hashes map; alternatively enforce/document the
contract on ConfigPoller.GetRouterConfig (and update splitConfigPoller if
needed) to always initialize response.Hashes, but the simplest fix is to check
response.Hashes != nil (and handle/mask missing keys) before reading
response.Hashes[""] in the function that builds the base graph mux.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@router/core/graph_server.go`:
- Around line 592-595: The current logger.Debug call reads
opts.hashes[featureFlagName].NewHash without verifying the key exists, which can
log empty hashes for flags skipped due to fetch failures; update the logic
around the Debug call in graph_server.go (the block that logs "Will reuse
feature flag mux for new graph server" referencing featureFlagName and
opts.hashes) to first check for the presence of opts.hashes[featureFlagName],
and if missing emit an alternate, clear message (e.g., indicate the flag was
skipped/stale due to prior fetch failure) while preserving the original debug
message when the hash exists; ensure this change handles the
SkipMissingFeatureFlags/featureFlagConfigs case so operators see distinct logs
for reused muxes with valid hashes vs skipped/stale flags.

---

Nitpick comments:
In `@router/core/graph_server.go`:
- Around line 369-370: The log line assumes response.Hashes and
response.Hashes[""] exist; add defensive nil/exists checks before accessing
NewHash (e.g., verify response != nil, response.Hashes != nil and that the key
"" exists) in the graph server code path that contains
s.logger.With(...).Debug(...) so you only reference response.Hashes[""].NewHash
when safe and fall back to a safe placeholder or skip the field when absent.
- Around line 351-354: The log accesses response.Hashes[""] without guarding
against a nil map; add a defensive nil-check (or zero-value fallback) before
indexing response.Hashes in the graph server code path that logs the hashes (the
variables referenced as response.Hashes[""].OldHash / NewHash) so you don't
panic if a ConfigPoller implementation returns a nil Hashes map; alternatively
enforce/document the contract on ConfigPoller.GetRouterConfig (and update
splitConfigPoller if needed) to always initialize response.Hashes, but the
simplest fix is to check response.Hashes != nil (and handle/mask missing keys)
before reading response.Hashes[""] in the function that builds the base graph
mux.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4b63fa64-26c8-4886-93b5-72579511cc87

📥 Commits

Reviewing files that changed from the base of the PR and between d0ff7b9 and 696acf6.

📒 Files selected for processing (3)
  • router/core/graph_server.go
  • router/pkg/controlplane/configpoller/split_config_poller.go
  • router/pkg/routerconfig/client.go

Comment thread router/core/graph_server.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
router/pkg/controlplane/configpoller/split_config_poller_test.go (1)

260-261: ⚡ Quick win

Use explicit assertions for hash presence/absence.

The current assertions are ambiguous:

  • Line 260: assert.Empty(t, resp.Hashes["missing"]) passes whether the key is absent or present with a zero-value HashInfo{}. According to the contract (context snippet 1), skipped flags should not be in the map at all.
  • Line 261: assert.NotEmpty is less specific than validating the actual hash value.

For consistency with other tests (lines 88, 133-134, 490-491) and clearer contract verification, consider:

assert.NotContains(t, resp.Hashes, "missing", "skipped flag must not appear in Hashes")
assert.Equal(t, routerconfig.HashInfo{NewHash: "hash-available"}, resp.Hashes["available"])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@router/pkg/controlplane/configpoller/split_config_poller_test.go` around
lines 260 - 261, Replace the ambiguous assertions on resp.Hashes: instead of
assert.Empty(t, resp.Hashes["missing"]) and assert.NotEmpty(t,
resp.Hashes["available"]), assert that the "missing" key is not present and
verify the exact HashInfo for "available"; specifically use
assert.NotContains(t, resp.Hashes, "missing", "skipped flag must not appear in
Hashes") and assert.Equal(t, routerconfig.HashInfo{NewHash: "hash-available"},
resp.Hashes["available"]) so the test checks absence vs exact value presence for
resp.Hashes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@router/pkg/controlplane/configpoller/split_config_poller_test.go`:
- Around line 260-261: Replace the ambiguous assertions on resp.Hashes: instead
of assert.Empty(t, resp.Hashes["missing"]) and assert.NotEmpty(t,
resp.Hashes["available"]), assert that the "missing" key is not present and
verify the exact HashInfo for "available"; specifically use
assert.NotContains(t, resp.Hashes, "missing", "skipped flag must not appear in
Hashes") and assert.Equal(t, routerconfig.HashInfo{NewHash: "hash-available"},
resp.Hashes["available"]) so the test checks absence vs exact value presence for
resp.Hashes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b9946685-0bf5-4e9c-9b1a-717be8ef4795

📥 Commits

Reviewing files that changed from the base of the PR and between 696acf6 and b809ee1.

📒 Files selected for processing (3)
  • router/pkg/controlplane/configpoller/split_config_poller.go
  • router/pkg/controlplane/configpoller/split_config_poller_test.go
  • router/pkg/routerconfig/client.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • router/pkg/routerconfig/client.go
  • router/pkg/controlplane/configpoller/split_config_poller.go

@dkorittki dkorittki marked this pull request as ready for review June 10, 2026 11:26
@dkorittki dkorittki requested a review from a team as a code owner June 10, 2026 11:26
Comment thread router/pkg/controlplane/configpoller/split_config_poller.go
Comment thread router/pkg/routerconfig/client.go
@dkorittki dkorittki merged commit 09679a7 into main Jun 11, 2026
36 checks passed
@dkorittki dkorittki deleted the dominik/eng-9706-log-engine-config-hashes branch June 11, 2026 07:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants