Repository navigation
Keep at most one fallback frontend poll in flight - #89
Merged
alexanderoster merged 2 commits intoOct 23, 2026
Merged
Conversation
When the event stream is unavailable, the client polls /api/frontend every 600 ms. Each tick sent a request whether or not the previous one had returned, so a server slower than the interval got an ever growing number of overlapping requests: more load on a server that is already behind. In a browser against a server answering polls after 3 s, five polls were in flight at once and the queued ones ran into the 10 s request timeout, because they also took the browser's connections. The reply serials only dropped out-of-order results; the requests still went out. A tick is now skipped while a request sent by retrieveFrontendState is pending (frontendRequestsInFlight), so a poll tick never adds a second request and the effective interval stretches to the server's response time. The counter is released however the request ends; the default 10 s timeout of axiosGetRequest bounds how long a hung request holds polling back. Navigation refreshes are not held back: the new page's values are needed at once, and the existing serials keep an older poll reply from overwriting them. A poll still pending when the stream takes over is dropped as before but keeps the gate until it settles, also if the client falls back to polling again in the meantime. Each tick also calls updateModules, which is what refreshes module data such as parameter lists and logs while polling. A skipped tick skips that too, so with a slow /api/frontend those modules are refreshed once per reply rather than every 600 ms, even if their own endpoints are fast. A server that slow is likely slow for them as well. The other periodic client requests (parameter list, logs, configuration list, part list, execution list deltas) already allow one request at a time. The change is in Client/core, so it applies to both the Vue and the Svelte client.
Client/core is framework-agnostic ES module code, so it can be tested under plain node without a browser or the client's npm packages. Client/tests is a small harness for that: support/coreLoader.mjs imports core modules through loader hooks (support/coreLoaderHooks.mjs) that load core's .js files as ES modules and replace the third-party imports (axios, luxon, three) with stubs. There are no dependencies; run "npm test" in Client/tests, or "node --test 'Client/tests/*.test.mjs'" from the repository root. frontendPollGate.test.mjs covers the gate from the previous commit: its release on reply, error and timeout, a server slower than the interval, a navigation refresh during a pending poll, and switching to the stream and back. Loading AMCApplication.js imports the list modules, which need Client/core/common/AMCListDeltaSync.js, so the tests require that file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When the event stream is unavailable, the client polls /api/frontend every 600 ms, even if the previous request hasn't returned. On a server slower than that, the requests pile up: against one answering in 3 s, five were in flight at once and the queued ones hit the 10 s request timeout.
A poll tick is now skipped while an /api/frontend request is still pending, so the interval stretches to the server's response time. A hung request holds polling back for at most the existing 10 s request timeout. Navigation refreshes are not held back.
A skipped tick also skips updateModules, so while polling, parameter lists, logs and similar data refresh once per reply instead of every 600 ms.
The change is in Client/core, so it covers both the Vue and Svelte clients.
NB: PR #88 dependency:
The second commit adds node:test tests in Client/tests/ (no npm dependencies; run npm test there). They need AMCListDeltaSync.js from #88, so merge this after #88. If you don't want a JS test setup in the repo, the first commit works on its own.