A synchronous SHOW in onWebClientStarted permanently blocks every later form open on that connection
Environment
- lsFusion 7.0-SNAPSHOT (server build 392), client war of the same build
- Apache Tomcat 9.0.121, Java 17.0.9, PostgreSQL 18, Windows 10
- Browser: Chromium (verified headless via Playwright; same behavior in the regular web client)
Minimal reproduction
MODULE Repro;
REQUIRE SystemEvents;
FORM home 'Home'
OBJECTS h = INTEGER
PROPERTIES VALUE(h)
;
FORM other 'Other'
OBJECTS o = INTEGER
PROPERTIES VALUE(o)
;
NAVIGATOR {
NEW other FIRST;
}
// opens at web client start — WITHOUT NOWAIT (synchronous)
onWebClientStarted() + {
SHOW home DOCKED;
}
Steps:
- Open the web client —
home renders fine (docked).
- Click Other in the navigator.
- The tab appears with a
"Loading" spinner (loading-async-icon) and stays there forever.
- Every other navigator entry behaves the same, until the browser tab is closed.
What makes it hard to diagnose:
- No errors in the server log.
- No browser console errors.
- No failed or hanging HTTP requests — the client keeps polling
POST /main/dispatch, each answered with an empty ClientMessageResult.
Server-side diagnosis
jstack of the app server while the client is stuck shows the per-connection navigator thread parked for the whole life of the form opened by the launch handler:
"pool-97-navigator-pausable-daemon-1" ... in Object.wait()
at lsfusion.server.logics.action.controller.context.ExecutionContext.requestFormUserInteraction(ExecutionContext.java:733)
at lsfusion.server.logics.action.controller.context.ExecutionContext.createAndRequestFormInstance(ExecutionContext.java:827)
at lsfusion.server.logics.form.open.interactive.FormInteractiveAction.executeInternal(FormInteractiveAction.java:172)
at lsfusion.server.logics.form.open.FormAction.executeInternal(FormAction.java:109)
...
at lsfusion.server.logics.navigator.controller.remote.RemoteNavigator.runAction(RemoteNavigator.java:833)
So the synchronous SHOW never completes (it waits for home to close), and all subsequent remote actions of that connection serialize behind the paused invocation. The client shows the async-loading panel and silently waits.
Expected behavior
At least one of:
- Docs:
Launch_events / the onWebClientStarted handler and the SHOW operator docs should state that a synchronous SHOW inside a launch-event handler blocks every later form open on that connection, and that NOWAIT must be used there. Right now the WAIT/NOWAIT heuristic ("the operator works synchronously when the current session may still be used afterwards") picks the synchronous mode silently, and nothing hints at the failure mode.
- Platform: treat launch-event handlers as implicitly async (equivalent of forcing
NOWAIT there), or don't serialize the connection's action queue behind an invocation that is parked waiting for a form it just opened.
Workaround
onWebClientStarted() + {
SHOW home DOCKED NOWAIT;
}
With NOWAIT everything works: the form opens, and subsequent navigator opens proceed normally (verified on the same build — flipping only this keyword un-hangs the client).
A synchronous
SHOWinonWebClientStartedpermanently blocks every later form open on that connectionEnvironment
Minimal reproduction
Steps:
homerenders fine (docked)."Loading"spinner (loading-async-icon) and stays there forever.What makes it hard to diagnose:
POST /main/dispatch, each answered with an emptyClientMessageResult.Server-side diagnosis
jstackof the app server while the client is stuck shows the per-connection navigator thread parked for the whole life of the form opened by the launch handler:So the synchronous
SHOWnever completes (it waits forhometo close), and all subsequent remote actions of that connection serialize behind the paused invocation. The client shows the async-loading panel and silently waits.Expected behavior
At least one of:
Launch_events/ theonWebClientStartedhandler and theSHOWoperator docs should state that a synchronousSHOWinside a launch-event handler blocks every later form open on that connection, and thatNOWAITmust be used there. Right now the WAIT/NOWAIT heuristic ("the operator works synchronously when the current session may still be used afterwards") picks the synchronous mode silently, and nothing hints at the failure mode.NOWAITthere), or don't serialize the connection's action queue behind an invocation that is parked waiting for a form it just opened.Workaround
With
NOWAITeverything works: the form opens, and subsequent navigator opens proceed normally (verified on the same build — flipping only this keyword un-hangs the client).