mirror of
https://github.com/morluto/rea.git
synced 2026-11-14 18:52:48 +00:00
fix(filesystem): retain stable hash cleanup owners across callers
Preserve completed digests and primary failures when descriptor close fails. Carry the exact handle owner through provider, readiness, cache, doctor and verifier boundaries, and retry cleanup without rehashing or retrying a raw fd. Close candidate-owned resources even when no target client was opened. Keep verifier workspaces when provider shutdown remains incomplete. Refs #4266
This commit is contained in:
1 parent
034293df14
commit
131fd5ddcd
24 files changed
+1313
-139
No files matched your search
@@ -7,6 +7,7 @@ import type { AnalysisProfileCommitment } from "../../domain/analysisProfile.js"
|
||||
import type { BinaryTarget } from "../../domain/binaryTargetTypes.js";
|
||||
import { AnalysisCancelledError } from "../../domain/analysisErrorCore.js";
|
||||
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
|
||||
import { ProviderCleanupError } from "../../domain/providerCleanupError.js";
|
||||
import {
|
||||
ProviderSelectionError,
|
||||
type ProviderSelectionFailureReason,
|
||||
@@ -135,6 +136,28 @@ export class AnalysisProviderRegistry {
|
||||
);
|
||||
}
|
||||
|
||||
/** Close candidate-owned resources even when no target client was opened. */
|
||||
async closeOwnedResources(): Promise<Result<null, AnalysisError>> {
|
||||
const failures: AnalysisError[] = [];
|
||||
for (const provider of this.#providers) {
|
||||
if (provider.closeOwnedResources === undefined) continue;
|
||||
const result = await provider.closeOwnedResources();
|
||||
if (!result.ok) failures.push(result.error);
|
||||
}
|
||||
if (failures.length === 0) return ok(null);
|
||||
if (failures.length === 1) return err(failures[0]!);
|
||||
return err(
|
||||
new ProviderCleanupError(
|
||||
"rea",
|
||||
failures.flatMap((failure) => failure.cleanupResources),
|
||||
{
|
||||
reason: failures.map((failure) => failure.message).join("; "),
|
||||
},
|
||||
{ cause: new AggregateError(failures) },
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/** List the unique deep-operation declarations without probing candidates. */
|
||||
declaredOperations(): readonly string[] {
|
||||
return [...this.#declaredOperations];
|
||||
|
||||
@@ -499,15 +499,26 @@ export class BinarySession
|
||||
if (clearRecords) this.clearSessionRecords();
|
||||
this.#clearRuntimeAvailability();
|
||||
const fileResources = await this.closeWriteResources();
|
||||
const candidates = await this.#providerRouter.closeOwnedResources();
|
||||
let lifecycle: Result<null, AnalysisError>;
|
||||
if (!closed.ok && !fileResources.ok)
|
||||
return err(
|
||||
lifecycle = err(
|
||||
analysisErrorWithCleanupFailure(
|
||||
closed.error,
|
||||
fileResources.error,
|
||||
"close_binary",
|
||||
),
|
||||
);
|
||||
return closed.ok ? fileResources : closed;
|
||||
else lifecycle = closed.ok ? fileResources : closed;
|
||||
if (!lifecycle.ok && !candidates.ok)
|
||||
return err(
|
||||
analysisErrorWithCleanupFailure(
|
||||
lifecycle.error,
|
||||
candidates.error,
|
||||
"close_binary",
|
||||
),
|
||||
);
|
||||
return lifecycle.ok ? candidates : lifecycle;
|
||||
}
|
||||
|
||||
async #retireClient(
|
||||
|
||||
@@ -70,6 +70,11 @@ export class SessionProviderRouter {
|
||||
return this.route;
|
||||
}
|
||||
|
||||
/** Close provider owners not represented by the currently bound client. */
|
||||
closeOwnedResources() {
|
||||
return this.registry.closeOwnedResources();
|
||||
}
|
||||
|
||||
/** Resolve target routes before any provider client is created. */
|
||||
async resolve(
|
||||
target: BinaryTarget,
|
||||
|
||||
Reference in new issue
Block a user