client, test/suites: forward session timeout cause over websocket - #1519
client, test/suites: forward session timeout cause over websocket#1519shardool-patil wants to merge 2 commits into
Conversation
roosterfish
left a comment
There was a problem hiding this comment.
Thanks for taking a look at this, please see my comments on the test.
There was a problem hiding this comment.
Pull request overview
This PR improves MicroCloud’s WebSocket session handling so that when a trust establishment session expires, the client receives the real cancellation cause (e.g., “Session timeout exceeded”) rather than a generic abnormal WebSocket EOF error, aligning behavior with issue #1245.
Changes:
- Adjusts the WebSocket gateway close-path to reliably send a
ControlClosemessage even when the gateway context is canceled. - Improves receive behavior to surface the gateway context cause when the receive channel closes.
- Adds a system test intended to validate that both initiator and joiner surface the timeout error.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| client/websocket.go | Ensures close-cause forwarding works reliably and improves receive-side error reporting when the socket closes. |
| test/suites/basic.sh | Adds an interactive test case intended to validate session-timeout error propagation to initiator/joiner. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
@roosterfish i have addressed all the requested changes:
take a look whenever possible |
b287951 to
4ffe082
Compare
|
See the test failure https://github.com/canonical/microcloud/actions/runs/32477357735/job/96766897819?pr=1519#step:3:45500. |
4ffe082 to
14a4c0b
Compare
@roosterfish I have worked and handled the requested changes so take a look at the code. |
14a4c0b to
c3f95c6
Compare
|
@roosterfish I switched the test to |
c3f95c6 to
e98fe8e
Compare
|
@roosterfish I've updated
Please take a look at this setup before re-running the tests. |
| // Send close control message. | ||
| // Try to send the cause from the outer context if present. | ||
| _ = gw.WriteClose(context.Cause(gwCtx)) | ||
| cause := context.Cause(gwCtx) |
There was a problem hiding this comment.
Don't we always have to write the close message? From what I remember it's important that it's of type ControlClose, but we don't have to populate the ControlMessage if there isn't any error.
There was a problem hiding this comment.
Here we will only ever send the control message if context.Cause returns a non-nil error.
| // It waits for the other side to hang up or the gateway's context being cancelled. | ||
| func (w *WebsocketGateway) WriteClose(err error) error { | ||
| writeErr := w.Write(ControlClose{ | ||
| w.writeLock.Lock() |
There was a problem hiding this comment.
Why the extra lock? By invoking w.Write, it already obtains the lock for us. I don't see why we have to use w.conn.WriteJSON directly here.
There was a problem hiding this comment.
thanks for pointing that out, i have removed the manual lock and reverted to write close
| set -eu | ||
| if [ "${SKIP_SETUP_LOG}" = 1 ]; then | ||
| exec > /dev/null 2>&1 | ||
| exec > /dev/null |
There was a problem hiding this comment.
Why is this necessary?
There was a problem hiding this comment.
this was an accidental edit left from local debugging, reverted microcloud.sh back to main.
| pkill -f \"ceph-osd .* --id \${osd}\" | ||
| microceph.ceph osd purge \${osd} --yes-i-really-mean-it --force | ||
| microceph.ceph osd destroy \${osd} --yes-i-really-mean-it --force | ||
| microceph.ceph osd purge \${osd} --yes-i-really-really-mean-it --force |
There was a problem hiding this comment.
Why is this necessary? According to ceph osd purge -h it's --yes-i-really-mean-it.
e0eafdf to
e5601b6
Compare
| lxc exec micro01 -- tail -1 out | grep "User aborted" -q | ||
| lxc exec micro04 -- tail -1 out | grep "Failed waiting during join: Initiator aborted the setup" -q | ||
|
|
||
| # Initiate a MicroCloud cluster with a session timeout and verify both initiator and joiner receive "Session timeout exceeded". |
There was a problem hiding this comment.
Please make sure the changes are separated into multiple commits (as you did before).
There was a problem hiding this comment.
i have separated the commits so take a look @roosterfish
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
test/suites/basic.sh:447
- The new test claims a short session timeout, but
join_sessionrunsmicrocloud init/addwith a hard-coded--session-timeout=60(seetest/includes/microcloud.sh:200-204). As written, this test will likely wait ~60s for the session to expire, which slows the suite and doesn’t match the PR description (SESSION_TIMEOUT=5). Consider making the timeout configurable (e.g., env var) and setting it to 5 for this case.
# Initiate a MicroCloud cluster with a session timeout and verify both initiator and joiner receive "Session timeout exceeded".
reset_systems 3 0 0
unset_interactive_vars
echo "Initiate a MicroCloud cluster with a short session timeout and verify both initiator and joiner receive the timeout error"
| func (w *WebsocketGateway) Write(v any) error { | ||
| w.writeLock.Lock() | ||
| defer w.writeLock.Unlock() | ||
|
|
||
| if w.ctx.Err() != nil { | ||
| return context.Cause(w.ctx) | ||
| } | ||
|
|
||
| return w.conn.WriteJSON(v) |
Signed-off-by: Shardool Patil <shardoolpatil999@gmail.com>
Signed-off-by: Shardool Patil <shardoolpatil999@gmail.com>
e5601b6 to
b1cfb10
Compare
Description
When a trust establishment session expires, the client previously received a generic connection error (
websocket: close 1006: unexpected EOF) instead of the actual cause (Session timeout exceeded)[cite: 5].Changes
client/websocket.go:WriteCloseto writeControlClosedirectly over the WebSocket underwriteLockso close frames are sent even whengwCtxis canceled on timeout[cite: 5].ReceiveWithContextto check channel closure and returncontext.Cause(w.ctx)[cite: 5].test/suites/basic.sh:test_interactivewithSESSION_TIMEOUT="5"verifying that both the initiator and joiner receive"Session timeout exceeded"[cite: 2].Checklist
Related issues
@roosterfish i have taken into consideration the insights you provided and resolved the issue, so take a look at it when you get time.