SDK-6983: rescue SDK-log upload on signal termination (v8 port of #86)#87
SDK-6983: rescue SDK-log upload on signal termination (v8 port of #86)#87kamal-kaur04 wants to merge 4 commits into
Conversation
Port of the v9 fix (SDK-6983-flush-on-signal): killed runs lose the logs.tar.gz upload because it only runs in launcher.onComplete. Rescue it from the exit-time detached cleanup (--uploadLogs, gated by a logsUploaded flag), snapshot funnelData credentials before fireFunnelRequest redacts them in place, and forward exitSignal/exitReason on StopBinSession so the binary stamps finished_metadata (v8 already had signal capture, user_killed funnel telemetry, and killSignal-aware stopBuildUpstream). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
🔴 SDK PR Review gate is red. Pending:
It turns green once the latest SDK PR Review Agent run reports GTG on the current head commit. A native reviewer approval is separately required by branch protection before merge. |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
🔴 SDK PR Review gate is red. Pending:
It turns green once the latest SDK PR Review Agent run reports GTG on the current head commit. A native reviewer approval is separately required by branch protection before merge. |
07souravkunda
left a comment
There was a problem hiding this comment.
Claude Code Review (automated) — 2 inline finding(s). Full report in the PR comment below. Verdict: Failed - see PR comment.
| process.on(sig, () => { | ||
| BStackLogger.debug(`${sig} received, setting kill signal`) | ||
| BrowserStackConfig.getInstance().setKillSignal(sig) | ||
| process.env[BROWSERSTACK_KILL_SIGNAL] = sig |
There was a problem hiding this comment.
HIGH — signal handlers never re-exit. Same as #86: the handler only sets the kill flag + env, never process.exit()/re-raises. SIGTERM/SIGHUP/SIGQUIT/SIGABRT no longer terminate the process — it hangs until CI sends SIGKILL, which fires no 'exit' event, so the cleanup child never spawns and the log-upload rescue this PR adds may not fire in its own target scenario. Drive a deterministic exit after stamping the signal, without preempting WDIO's graceful shutdown.
There was a problem hiding this comment.
Fixed in aec8d08 — same treatment as #86: after stamping the kill flag/env, the listener arms an unref()'d 5s grace timer that forces process.exit(128 + n) (SIGTERM→143) if nothing else has terminated the process. process.exit fires the 'exit' listener, so the detached cleanup child (and this PR's --uploadLogs rescue) runs even on the hung-shutdown path; a naturally exiting run is unaffected. Unit-tested with fake timers.
| if (response) { | ||
| // A delivered upload must not be repeated by the exit-time | ||
| // cleanup rescue. | ||
| this.browserStackConfig.logsUploaded = true |
There was a problem hiding this comment.
LOW — logsUploaded set only on a truthy response. An upload that succeeds with an empty body leaves the flag false, so the detached cleanup child re-uploads. Wasteful, not harmful.
There was a problem hiding this comment.
Fixed in aec8d08 — also covered the inverse case: a truthy server rejection (response.status !== 'success') previously marked logsUploaded = true, disabling the rescue for an upload that never landed. Now gated on delivered = !!response && !(response.status && response.status !== 'success'). Empty-body success remains indistinguishable from transport failure on this path, so it stays rescue-eligible (wasteful-but-safe). Unit-tested.
Claude Code Review — PR #87SDK-6983: rescue SDK-log upload on signal termination (v8 port of #86) Narrower port of #86: the SDK-log-upload rescue (detached cleanup child re-uploads via Findings1 · HIGH · Correctness — signal handlers never re-exit — 2 · LOW · Efficiency — 3 · LOW · Consistency — detached child Scope note (not a defect)On v8 the kill reason is forwarded to the binary only through the gRPC stop request ( Verified clean
Verdict: FAIL — one High-severity correctness finding (#1), identical to #86. Automated review. Findings verified against the branch head and the proto contract reachable from the repo. |
…aded on delivery Signal listeners suppress Node's default termination, so a hung shutdown never fires 'exit' and skips the cleanup rescue — force a 128+n exit after a grace window. Only mark logsUploaded when the server actually accepted the upload (a truthy response can still carry a non-success status). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
🔴 SDK PR Review gate is red. Pending:
It turns green once the latest SDK PR Review Agent run reports GTG on the current head commit. A native reviewer approval is separately required by branch protection before merge. |
Claude Code Review — PR #87 (re-review)Head Prior findings — all resolved#1 (HIGH) signal handlers never re-exit → ✅ resolved. Same fix as #86: #2 (LOW) Non-blocking notes
Verdict: PASS — the High-severity issue is fixed correctly; only non-blocking consistency/scope notes remain. |
|
🔴 SDK PR Review gate is red. Pending:
It turns green once the latest SDK PR Review Agent run reports GTG on the current head commit. A native reviewer approval is separately required by branch protection before merge. |
|
🟢 SDK PR Review Agent — GTG on head The prior High-severity signal-handler finding is fixed correctly ( Verdict: PASS. (A native GitHub reviewer approval is still separately required by branch protection before merge.) |
|
🟢 SDK PR Review gate is green — the SDK PR Review Agent has given a GTG for this PR (the A native GitHub reviewer approval is still separately required by branch protection before this PR can merge — this check does not substitute for that. |
1 similar comment
|
🟢 SDK PR Review gate is green — the SDK PR Review Agent has given a GTG for this PR (the A native GitHub reviewer approval is still separately required by branch protection before this PR can merge — this check does not substitute for that. |
What is this about?
Port of the v9 fix (#86) to the v8 line, for SDK-6983 (Bucket E — terminated runs): a signal-terminated run's
logs.tar.gzupload only happens inlauncher.onComplete, which a kill never reaches or cuts short — killed wdio-8 builds land with no SDK-log object in S3 (kill-matrix validation on production 8.48.0: 3/3 killed cucumber and 2/3 killed mocha builds had no log object).The v8 line already has the signal machinery the v9 port had to add (signal capture,
user_killedfunnel telemetry, killSignal-awarestopBuildUpstream, SIGINT to the CLI child) — this PR adds only what it lacks:cleanup.jstakes--uploadLogs <clientBuildUuid>and uploadslogs.tar.gzwhen the launcher's own upload never ran — gated by alogsUploadedflag so delivered uploads are never repeated.fireFunnelRequestredactsfunnelDatacredentials in place; cleanup snapshots them before the funnel send so the rescue doesn't authenticate as[REDACTED].exitSignal/exitReason(user_killed) onStopBinSessionRequestso the binary stampsfinished_metadataon the build stop (the direct-flow stop already stamps it on v8).Validation (wdio 8 mocha sample, mid-spec SIGTERM, this branch): exit 143, cleanup rescue fired, killed build's full log tar (1.9MB: service + CLI debug logs) present in the SDK-logs S3 bucket; baseline behavior unchanged. Evidence: workspace
work/tra-session-linking-instability-split/E/FIX-flush-on-signal-validation.md.Companion PRs (same lane): #86 (v9), browserstack/browserstack-node-agent#2344, browserstack/browserstack-javaagent#2102.
Related Jira task/s
Release (mandatory for every PR — required for the
ready-for-reviewlabel)Version bump: (required — tick exactly one)
Release notes type: (optional)
Release notes (customer-facing): (optional but encouraged)
Release notes (internal):
cleanup.jsrescues thelogs.tar.gzupload for signal-terminated runs (--uploadLogs, gated bylogsUploaded); funnelData credentials snapshotted beforefireFunnelRequest's in-place redaction;StopBinSessionRequestcarriesexitSignal/exitReasonso the binary stampsfinished_metadata(SDK-6983, port of SDK-6983: upload SDK logs and emit kill telemetry on signal termination #86).Checklist
PR Validations
Run Tests: Comment RUN_TESTS to trigger sanity tests.
🤖 Generated with Claude Code