mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 16:50:43 +00:00
fix(gateway): capture config hash after plugin auto-enable to prevent restart loop (#67557)
Merged via squash.
Prepared head SHA: 07250958a7
Co-authored-by: openperf <80630709+openperf@users.noreply.github.com>
Co-authored-by: openperf <80630709+openperf@users.noreply.github.com>
Reviewed-by: @openperf
This commit is contained in:
@@ -620,6 +620,34 @@ describe("startGatewayConfigReloader", () => {
|
||||
|
||||
await harness.reloader.stop();
|
||||
});
|
||||
|
||||
it("does not dedupe when initialInternalWriteHash is null (#67436)", async () => {
|
||||
const readSnapshot = vi
|
||||
.fn<() => Promise<ConfigFileSnapshot>>()
|
||||
.mockResolvedValueOnce(
|
||||
makeSnapshot({
|
||||
config: {
|
||||
gateway: { reload: { debounceMs: 0 }, auth: { mode: "token", token: "startup" } },
|
||||
},
|
||||
hash: "startup-internal-1",
|
||||
}),
|
||||
);
|
||||
const harness = createReloaderHarness(readSnapshot, {
|
||||
initialInternalWriteHash: null,
|
||||
});
|
||||
|
||||
harness.watcher.emit("change");
|
||||
await vi.runOnlyPendingTimersAsync();
|
||||
|
||||
expect(readSnapshot).toHaveBeenCalledTimes(1);
|
||||
// With a null hash the guard is a no-op, so the reload proceeds and
|
||||
// detects a config diff → restart. This is the pre-fix regression
|
||||
// scenario from #67436 where plugin auto-enable was the only startup
|
||||
// writer and the hash was never captured.
|
||||
expect(harness.onRestart).toHaveBeenCalledTimes(1);
|
||||
|
||||
await harness.reloader.stop();
|
||||
});
|
||||
});
|
||||
|
||||
describe("shouldInvalidateSkillsSnapshotForPaths", () => {
|
||||
|
||||
@@ -284,7 +284,14 @@ export async function startGatewayServer(
|
||||
log,
|
||||
});
|
||||
cfgAtStart = controlUiSeed.config;
|
||||
if (authBootstrap.persistedGeneratedToken || controlUiSeed.persistedAllowedOriginsSeed) {
|
||||
// Always capture the final config hash after all startup writes (plugin
|
||||
// auto-enable, auth token generation, control-UI origin seeding) so the
|
||||
// config reloader can recognize its own startup writes and suppress the
|
||||
// spurious hot-reload that would otherwise trigger a SIGUSR1 restart loop.
|
||||
// Previously the hash was only captured when auth or control-UI persisted
|
||||
// changes, missing the plugin auto-enable write performed earlier inside
|
||||
// loadGatewayStartupConfigSnapshot(). See #67436.
|
||||
{
|
||||
const startupSnapshot = await readConfigFileSnapshot();
|
||||
startupInternalWriteHash = startupSnapshot.hash ?? null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user