feat: support manifest for local development - #2892
Conversation
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Tip: disable this comment in your organization's Code Review settings.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughRouter now loads and hot-reloads execution configuration from a "manifest" directory (split into ChangesManifest Config Loading and Hot-Reload
🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Router image scan passed✅ No security vulnerabilities found in image: |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #2892 +/- ##
===========================================
+ Coverage 40.86% 66.18% +25.32%
===========================================
Files 1037 258 -779
Lines 131332 27221 -104111
Branches 6176 0 -6176
===========================================
- Hits 53672 18017 -35655
+ Misses 75914 7769 -68145
+ Partials 1746 1435 -311
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (1)
router/pkg/config/config.go (1)
1049-1050: ⚡ Quick winNamespace manifest env vars consistently with the other manifest fields.
SKIP_MISSING_FEATURE_FLAGS/IGNORED_FEATURE_FLAGSare currently unscoped, while the rest of this block usesEXECUTION_CONFIG_MANIFEST_*. Scoping these two as well improves predictability and avoids accidental global env overrides.Proposed diff
type ExecutionConfigManifest struct { Path string `yaml:"path,omitempty" env:"EXECUTION_CONFIG_MANIFEST_PATH"` - SkipMissingFeatureFlags bool `yaml:"skip_missing_feature_flags" envDefault:"false" env:"SKIP_MISSING_FEATURE_FLAGS"` - IgnoredFeatureFlags []string `yaml:"ignored_feature_flags,omitempty" env:"IGNORED_FEATURE_FLAGS"` + SkipMissingFeatureFlags bool `yaml:"skip_missing_feature_flags" envDefault:"false" env:"EXECUTION_CONFIG_MANIFEST_SKIP_MISSING_FEATURE_FLAGS"` + IgnoredFeatureFlags []string `yaml:"ignored_feature_flags,omitempty" env:"EXECUTION_CONFIG_MANIFEST_IGNORED_FEATURE_FLAGS"` Watch bool `yaml:"watch,omitempty" envDefault:"false" env:"EXECUTION_CONFIG_MANIFEST_WATCH"` WatchInterval time.Duration `yaml:"watch_interval,omitempty" envDefault:"1s" env:"EXECUTION_CONFIG_MANIFEST_WATCH_INTERVAL"` }🤖 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/config/config.go` around lines 1049 - 1050, The two struct fields SkipMissingFeatureFlags and IgnoredFeatureFlags use unscoped env tags; update their `env` tags to match the rest of the manifest block by prefixing with EXECUTION_CONFIG_MANIFEST_, i.e. change env:"SKIP_MISSING_FEATURE_FLAGS" to env:"EXECUTION_CONFIG_MANIFEST_SKIP_MISSING_FEATURE_FLAGS" and env:"IGNORED_FEATURE_FLAGS" to env:"EXECUTION_CONFIG_MANIFEST_IGNORED_FEATURE_FLAGS" on the SkipMissingFeatureFlags and IgnoredFeatureFlags fields respectively (leave the yaml tags and envDefault values as-is).
🤖 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 `@demo/build_manifest.py`:
- Around line 146-153: The mapper.json is written before other config files
which can trigger the manifest watcher on an incomplete state; change the write
order so that self.latest_config (and any other config files) are written first
via write_content_to_file (referencing latest_path and self.latest_config), then
write mapper.json (mapper_path with self.mapper) last so mapper.json mtime is
updated only after all other configs are persisted.
In `@router-tests/protocol/config_hot_reload_test.go`:
- Around line 515-551: The test uses time.Sleep and an atomic counter (done
atomic.Uint32) with two goroutines calling xEnv.MakeGraphQLRequestOK to wait for
both requests, which is flaky; replace this pattern by installing and using the
SyncReporter (inject into the router at test setup) and the existing wait
helpers (call e.syncReporter() or the appropriate WaitFor* helper) to await both
requests and config reload instead of sleep+atomic, and keep the
writeTestManifest("updated", manifestDir) and the require.EventuallyWithT reload
assertion; remove the atomic done, the two manual goroutines synchronization,
and use SyncReporter/Wait helpers to assert both requests completed and the
config version switched to "updated".
- Around line 970-972: The test currently writes mapper.json before the base
config, causing the watcher to see the mapper mtime update before latest.json
and miss the new manifest; move the writeTestMapper(...) call to run last so
mapper.json is written after writeBaseGraphConfig(...) (and after any
writeTestManifest(...) that updates latest.json), i.e. ensure
writeBaseGraphConfig and/or writeTestManifest are called first and then call
writeTestMapper so the mapper mtime reflects the final state.
In `@router/core/router.go`:
- Around line 1631-1640: The deferred call that sets readiness and emits the
"Server initialized" log (r.httpServer.healthcheck.SetReady(true) and
r.logger.Info(...)) is executed even when subsequent startup steps (watcher
creation/initialization) fail; move or conditionalize readiness/logging so it
only runs after all startup steps succeed: either remove the defer and place the
SetReady(true)/logger.Info(...) at the end of Start after watcher creation
succeeds, or change the defer to check the function's final error (use a named
return err and only set ready/log when err == nil). Update references in Start
that create watchers/initialize components so readiness is set only when those
succeed.
- Around line 1731-1733: The manifest watcher currently only watches
mapper.json; update the Paths slice construction (where Logger: ll, Paths:
[]string{filepath.Join(r.manifestConfig.Path, "mapper.json")}, Interval:
r.manifestConfig.WatchInterval) to include filepath.Join(r.manifestConfig.Path,
"latest.json") and the feature-flags patterns (e.g.
filepath.Join(r.manifestConfig.Path, "feature-flags", "*")) so changes to
latest.json or any file under feature-flags/ will trigger the hot-reload.
In `@router/pkg/routerconfig/routerconfig.go`:
- Line 77: AssembleConfig currently dereferences the incoming rules parameter
without a nil guard which causes a panic for callers passing nil; inside
AssembleConfig check if rules == nil and either return a clear error (e.g.,
fmt.Errorf("rules is nil")) or initialize a default AssembleConfigRules and
continue, ensuring subsequent uses (the code paths that read fields from rules)
never dereference a nil pointer; update AssembleConfig's error return path
accordingly so exported API returns an error instead of panicking.
- Around line 119-129: The code calling fs.ReadFile(fsys, key+".json") currently
only handles os.IsNotExist errors and lets other I/O errors fall through leaving
fileBytes invalid; update the error handling in the ReadFile block so that when
err != nil and os.IsNotExist(err) is false you immediately return the error
(e.g. wrap and return fmt.Errorf("reading feature flag %s: %w", key, err)); keep
the existing branch that continues on missing files when
rules.SkipMissingFeatureFlags is true. Reference: fs.ReadFile, fileBytes, err,
and rules.SkipMissingFeatureFlags.
---
Nitpick comments:
In `@router/pkg/config/config.go`:
- Around line 1049-1050: The two struct fields SkipMissingFeatureFlags and
IgnoredFeatureFlags use unscoped env tags; update their `env` tags to match the
rest of the manifest block by prefixing with EXECUTION_CONFIG_MANIFEST_, i.e.
change env:"SKIP_MISSING_FEATURE_FLAGS" to
env:"EXECUTION_CONFIG_MANIFEST_SKIP_MISSING_FEATURE_FLAGS" and
env:"IGNORED_FEATURE_FLAGS" to
env:"EXECUTION_CONFIG_MANIFEST_IGNORED_FEATURE_FLAGS" on the
SkipMissingFeatureFlags and IgnoredFeatureFlags fields respectively (leave the
yaml tags and envDefault values as-is).
🪄 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: f8855fbf-8f2f-4df7-8250-2ca75acc46de
📒 Files selected for processing (19)
demo/.gitignoredemo/Makefiledemo/build_manifest.pyrouter-tests/protocol/config_hot_reload_test.gorouter-tests/testenv/testdata/manifest/feature-flags/myff.jsonrouter-tests/testenv/testdata/manifest/latest.jsonrouter-tests/testenv/testdata/manifest/mapper.jsonrouter/.gitignorerouter/core/router.gorouter/core/router_config.gorouter/core/supervisor_instance.gorouter/pkg/config/config.gorouter/pkg/config/config.schema.jsonrouter/pkg/config/config_test.gorouter/pkg/config/json_schema.gorouter/pkg/config/testdata/config_defaults.jsonrouter/pkg/config/testdata/config_full.jsonrouter/pkg/routerconfig/routerconfig.gorouter/pkg/watcher/watcher.go
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@docs-website/router/configuration.mdx`:
- Line 1266: The sentence combines multiple clauses and has a typo: change the
verb "stats" to "watches" and split into two shorter sentences—one describing
what the manifest directory contains (mentioning mapper.json, latest.json, and
feature-flags/<name>.json) and a second stating that when watch is enabled the
router watches mapper.json and reloads the assembled config without downtime
whenever the file's mtime changes; update the sentence referencing "watch" and
"mapper.json" accordingly.
🪄 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: 029630ee-0e7b-4d2d-ae9c-dc48c6787f74
📒 Files selected for processing (2)
docs-website/router/configuration.mdxrouter/pkg/config/config.go
There was a problem hiding this comment.
🧹 Nitpick comments (2)
router-tests/protocol/config_hot_reload_test.go (1)
132-147: ⚡ Quick winPrefer
sync.WaitGroup.Gofor these test goroutines
Inrouter-tests/protocol/config_hot_reload_test.go(around 132-147, 375-390, 514-529), switch fromwg.Add(2)+defer wg.Done()+go func()towg.Go(func() { ... })for consistency with the repo’s existingsync.WaitGroup.Gousage (Go 1.25.0).🤖 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-tests/protocol/config_hot_reload_test.go` around lines 132 - 147, Replace the manual goroutine pattern (wg.Add(2) + go func() { defer wg.Done(); ... }) with the repo's sync.WaitGroup.Go helper: remove wg.Add and defer wg.Done, and call wg.Go(func() { ... }) for each concurrent test routine; apply this change to the blocks that call MakeGraphQLRequestOK and assert on RouterConfigVersionMain()/testutils.EmployeesIDData so the goroutines use wg.Go consistently (symbols to update: wg, wg.Go, MakeGraphQLRequestOK, RouterConfigVersionMain, testutils.EmployeesIDData).router/pkg/routerconfig/routerconfig.go (1)
41-41: 💤 Low valueUse
filepath.Joinfor path construction.String concatenation with
/is not portable. The rest of this file usesfilepath.Joinconsistently (lines 82, 94).♻️ Suggested fix
- mapperStat, err := os.Lstat(path + "/mapper.json") + mapperStat, err := os.Lstat(filepath.Join(path, "mapper.json"))🤖 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/routerconfig/routerconfig.go` at line 41, Replace the string-concatenation path used when calling os.Lstat on "mapper.json" with filepath.Join to follow the file's existing portable path handling; locate the call to os.Lstat(path + "/mapper.json") (referencing mapperStat and err) and change it to build the target file path via filepath.Join(path, "mapper.json") before passing it to os.Lstat so it matches other uses like the calls around lines using filepath.Join.
🤖 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-tests/protocol/config_hot_reload_test.go`:
- Around line 132-147: Replace the manual goroutine pattern (wg.Add(2) + go
func() { defer wg.Done(); ... }) with the repo's sync.WaitGroup.Go helper:
remove wg.Add and defer wg.Done, and call wg.Go(func() { ... }) for each
concurrent test routine; apply this change to the blocks that call
MakeGraphQLRequestOK and assert on
RouterConfigVersionMain()/testutils.EmployeesIDData so the goroutines use wg.Go
consistently (symbols to update: wg, wg.Go, MakeGraphQLRequestOK,
RouterConfigVersionMain, testutils.EmployeesIDData).
In `@router/pkg/routerconfig/routerconfig.go`:
- Line 41: Replace the string-concatenation path used when calling os.Lstat on
"mapper.json" with filepath.Join to follow the file's existing portable path
handling; locate the call to os.Lstat(path + "/mapper.json") (referencing
mapperStat and err) and change it to build the target file path via
filepath.Join(path, "mapper.json") before passing it to os.Lstat so it matches
other uses like the calls around lines using filepath.Join.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2182c885-3224-479d-b8c4-eac9be27d139
📒 Files selected for processing (5)
demo/build_manifest.pydocs-website/router/configuration.mdxrouter-tests/protocol/config_hot_reload_test.gorouter/core/router.gorouter/pkg/routerconfig/routerconfig.go
dkorittki
left a comment
There was a problem hiding this comment.
LGTM with some minor improvement ideas, feel free to implement them at will.
In general I feel a bit confused about the manifest name for the new config type. One is called "static execution config" and the other is called "manifest execution config". To me both are static and manifests, so these do not distinguish them for me. Maybe we can elaborate on the name again or describe it somewhere central in a godoc.
Also it would be great to have a place in our docs where we explain this concept to users. Currently we only have the new parameters listed on the routers config page.
|
Actionable comments posted: 0 |
Summary by CodeRabbit
New Features
Chores
Documentation
Tests
Checklist
Open Source AI Manifesto
This project follows the principles of the Open Source AI Manifesto. Please ensure your contribution aligns with its principles.