Repository navigation
Conversation
|
Reviewed; no blockers found. |
There was a problem hiding this comment.
Code Review
This pull request introduces changes to replication connection handling, specifically adding abortLateBlobReceiveAfterClose to handle late-attaching blob streams after a connection has closed, and extracts a helper function createReplicationConnectionClosedError. It also updates types in abortInFlightBlobsOnClose from any to string and adds corresponding unit tests. Feedback is provided to make the destroy method optional in abortLateBlobReceiveAfterClose to prevent potential runtime errors and maintain consistency with other stream-handling functions.
| export function abortLateBlobReceiveAfterClose( | ||
| connectionClosed: boolean, | ||
| stream: { writableEnded?: boolean; destroyed?: boolean; destroy: (error: Error) => void }, | ||
| remoteNodeName: string, | ||
| blobId: string | ||
| ): boolean { | ||
| if (!connectionClosed || stream.writableEnded || stream.destroyed) return false; | ||
| stream.destroy(createReplicationConnectionClosedError(remoteNodeName, blobId)); | ||
| return true; | ||
| } |
There was a problem hiding this comment.
In abortInFlightBlobsOnClose, the destroy method on the stream is treated as optional (destroy?), and there is even a unit test verifying that streams without a destroy method are tolerated. However, in abortLateBlobReceiveAfterClose, the stream parameter types destroy as a required method, and it is invoked directly without optional chaining. To prevent potential runtime TypeErrors and maintain consistency, destroy should be marked as optional and invoked using optional chaining.
export function abortLateBlobReceiveAfterClose(
connectionClosed: boolean,
stream: { writableEnded?: boolean; destroyed?: boolean; destroy?: (error: Error) => void },
remoteNodeName: string,
blobId: string
): boolean {
if (!connectionClosed || stream.writableEnded || stream.destroyed) return false;
stream.destroy?.(createReplicationConnectionClosedError(remoteNodeName, blobId));
return true;
}caa8404 to
7cb6a55
Compare
|
Answer recorded on #732: run 3 on Node 22 reproduced the original failure exactly (362.7s, cursor pinned at 13, Purpose served — closing. — Claude Opus 5 |
Do not merge. Do not review. This branch exists only to run one experiment on CI.
Question
harper-pro#732 fixes a blob-receive teardown race and ships a regression test. The pre-fix red was observed on CI Node 22 with the original test; #732 then changed the fault-injection pattern (now every five blob saves). The pre-fix code against the new test has never been measured, so it is unknown whether that test actually pins the fix.
Locally on macOS (Node 22.23.1) both arms pass 3/3 in ~20s — the pathological path never opens on this hardware, so the local result is uninformative rather than evidence either way.
Method
This branch is #732 at
c22a0bfcwith exactly one change: the ownership guard's condition is hardcoded tofalse, so production behavior equalsorigin/mainwhile the exported function and its unit tests stay intact. Everything else — the regression test, the workflow, the Node 22/24/26.5 focused job — is identical to #732.If
Copy-gap Runtime Regression (Node.js v22)goes red here and green on #732, the test pins the fix. If it goes green here, the test does not discriminate and #732's coverage claim needs revisiting (the original fault pattern may have been the load-bearing one).The race is intermittent (~2/3 pre-fix on the original test), so a single green result is weak; the job will be re-run a few times.
Closing this once the answer is recorded on #732.
— Claude Opus 5
Review-Coverage: authored=unknown; ran=none; rounds=1 @ 7cb6a55
Human-Review-Need: 4 @ 7cb6a55