mirror of
https://github.com/morluto/rea.git
synced 2026-11-10 08:47:00 +00:00
fix(browser): honor cancellation during CDP cleanup
Complete owned teardown before deciding whether a successful observation can be published. Classify an exactly propagated source-map abort reason as cancellation while preserving unrelated failures. Validation: all four cleanup/cancellation boundary tests pass, retaining detach, socket and target-liveness assertions. Based on #2893.
This commit is contained in:
1 parent
7cfcd166e3
commit
ad9e22d05f
2 files changed
+22
-2
No files matched your search
@@ -167,6 +167,11 @@ export class CdpBrowserProvider implements BrowserObservationPort {
|
||||
),
|
||||
);
|
||||
} catch (cause: unknown) {
|
||||
// fetchWebSourceMaps rethrows the exact abort reason. Preserve cancellation
|
||||
// even when a caller supplied an AnalysisError as that reason.
|
||||
if (options.signal?.aborted === true && cause === options.signal.reason) {
|
||||
return err(new AnalysisCancelledError("analyze_web_bundle", { cause }));
|
||||
}
|
||||
return err(providerError(cause, "analyze_web_bundle", options.signal));
|
||||
}
|
||||
}
|
||||
@@ -305,6 +310,7 @@ const withTargetSession = async <
|
||||
options.signal,
|
||||
);
|
||||
let targetSession: CdpTargetSession | undefined;
|
||||
let output: Output;
|
||||
try {
|
||||
const target = authorizeTarget(endpoint.discovery, input);
|
||||
const scopedInput = scopeToTargetOrigin(input, target);
|
||||
@@ -322,7 +328,7 @@ const withTargetSession = async <
|
||||
operation,
|
||||
options.signal,
|
||||
);
|
||||
return await work({
|
||||
output = await work({
|
||||
connection: targetSession.connection,
|
||||
sessionId: targetSession.sessionId,
|
||||
discovery: endpoint.discovery,
|
||||
@@ -341,6 +347,14 @@ const withTargetSession = async <
|
||||
// An unadopted browser socket is closed here; closing is idempotent.
|
||||
await endpoint.connection?.close();
|
||||
}
|
||||
|
||||
// Cancellation during teardown must not publish the completed observation.
|
||||
// Errors from work or cleanup still propagate through the try/finally above.
|
||||
if (options.signal?.aborted === true)
|
||||
throw new AnalysisCancelledError(operation, {
|
||||
cause: options.signal.reason,
|
||||
});
|
||||
return output;
|
||||
};
|
||||
|
||||
const selectTargets = (
|
||||
|
||||
@@ -73,7 +73,13 @@ it("releases cleanup when cancellation arrives after capture completes", async (
|
||||
});
|
||||
controller.abort();
|
||||
const result = await pending;
|
||||
expect(result.ok).toBe(true);
|
||||
expect(result).toMatchObject({
|
||||
ok: false,
|
||||
error: {
|
||||
_tag: "AnalysisCancelledError",
|
||||
operation: "observe_web_session",
|
||||
},
|
||||
});
|
||||
expect(browser.commands.map(({ method }) => method)).toContain(
|
||||
"Target.detachFromTarget",
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user