fix(sdk): Connect-envelope process.Process/Start and parse exit-0 end…#828
Conversation
|
Overall: fixes are correct and well-tested. A few notes:
|
… events Two fixes on the Go SDK Commands.Run path, both needed to run a process end-to-end against a real deployment. 1) Request framing (TencentCloud#825): startProcess sent the streaming /process.Process/Start body as raw JSON while advertising Content-Type: application/connect+json. For a server-streaming Connect RPC the request must be a 5-byte length-prefixed enveloped message, so envd read the leading JSON bytes as a frame header and aborted with "protocol error: promised <huge> bytes ... got N bytes". Wrap the body with a new encodeConnectEnvelope helper and send Connect-Content-Encoding: identity, matching the Python SDK and the Go PTY path; reuse the helper in watchDir, which inlined the same framing. 2) Exit-0 parsing: the end event is proto3 JSON, which omits a zero-valued exitCode entirely, so a successful (exit 0) process arrives as only {"exited":true,"status":"exit status 0"} and parseProcessStartStream failed with "process EndEvent missing exit code". Recover the code from the status string, then fall back to the exited flag, so exit-0 commands no longer spuriously fail. Verified against a live CubeSandbox (with the TencentCloud#816 envd-port fix applied): Commands.Run streams cleanly for exit 0 (multi-line stdout) and exit 3. Closes TencentCloud#825 Signed-off-by: chaojixinren <chaoji_xinren@163.com>
763dd48 to
e16803a
Compare
| } | ||
| req.Header.Set("Content-Type", connectContentType) | ||
| req.Header.Set("Connect-Protocol-Version", connectProtocolVersion) | ||
| req.Header.Set("Connect-Content-Encoding", "identity") |
There was a problem hiding this comment.
Suggestion: Add a comment explaining why Connect-Content-Encoding: identity is needed.
The Connect protocol supports gzip-compressed request bodies (via the compressed flag in the envelope + Connect-Content-Encoding: gzip). Setting this to identity explicitly signals to the server that the body is uncompressed. A brief comment here would help future readers understand why this header was added and when it matters.
// Explicitly signal uncompressed body so the Connect server does not
// attempt gzip decompression (the envelope flag byte is 0).
req.Header.Set("Connect-Content-Encoding", "identity")
PR Review: fix(sdk): Connect-envelope process.Process/Start and parse exit-0 end events (#828)OverviewClean, focused fix addressing two bugs on the Go SDK's Inline Comment
Code Quality1. Redundant error branching in This is pre-existing code, not introduced by this PR, but worth cleaning up. Security2. Potential spurious error from if err != nil {
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
return
}
if w.ctx.Err() != nil {
return // context was canceled — not a real error
}
w.sendErr(err)
return
}Pre-existing code, not introduced by this PR, but a meaningful API robustness improvement. Test Coverage — Gaps Worth Filling3.
Adding table-driven tests for 4. Missing
Comments & Documentation5. Comment on Summary
Overall this is a well-engineered fix with thorough E2E validation. The suggestions above are refinements, not blockers. |
Summary
Two fixes on the Go SDK's
Commands.Run(/process.Process/Start) path, bothrequired to run a process end-to-end against a real deployment:
Request framing ([Bug Report] Go SDK sends /process.Process/Start request body without a Connect envelope #825) —
startProcesssent the streaming request body asraw JSON while advertising
Content-Type: application/connect+json. Aserver-streaming Connect RPC requires a 5-byte length-prefixed enveloped
message, so envd read the leading JSON bytes (
{"pr…) as a frame header,decoded a bogus length, and aborted. Now wrapped via a new
encodeConnectEnvelopehelper +Connect-Content-Encoding: identity,matching the Python SDK and the Go PTY path.
watchDirreuses the samehelper (previously inlined identical framing).
Exit-0 end-event parsing — the end event is proto3 JSON, which omits a
zero-valued
exitCodeentirely, so a successful (exit 0) process arrives asonly
{"exited":true,"status":"exit status 0"}andparseProcessStartStreamfailed with
process EndEvent missing exit code. Now recovers the code fromthe
statusstring and falls back to theexitedflag, so exit-0 commands(the common case) no longer spuriously fail.
Changes
sdk/go/envd.goencodeConnectEnvelope; use it instartProcess+ setConnect-Content-Encoding: identity; refactorwatchDirto reuse it.processEndEvent.exitCode(): fall back to parsingstatus(exit status N)then the
exitedflag whenexitCode/exit_codeare absent.sdk/go/sdk_test.goTestCommandsRunUsesEnvdProcessStart: assert the request body is a validConnect envelope and
Connect-Content-Encoding: identity.TestProcessEndEventExitCode(table-driven) andTestCommandsRunExitZeroStatusOnly(exit-0 stream reproduction).Root cause (framing) — live A/B, same endpoint/port, only body framing differs
Raw JSON → envd's protocol framing error. The 5-byte-enveloped request runs
cleanly (
pid=11,stdout=aGkK= base64 ofhi\n,exit status 0). Theenvelope is the only variable.
Testing
go vet ./...clean;go test ./...green (unit tests, incl. the newenvelope + exit-0 coverage).
api=127.0.0.1:13000,proxy=127.0.0.1:11080,domain=cube.app), with the [Bug Report] Go SDK sends envd data-plane RPCs to the Jupyter port (49999) instead of envd (49983) #816 envd-port fixapplied so requests reach envd (
49983):Framing fix —
/process.Process/Startstreams cleanly:Exit-0 parsing fix — exit 0 and exit 3 both return correctly:
Notes
distinct bugs on the same code path. Unit tests do not catch either
(
httptestmocks never validate request framing and always include a nonzeroexitCode).parseProcessStartStream→readConnectEnvelope); only the request side and the exit-0 case were wrong.Closes #825