Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions apps/server/src/orchestration-v2/PullRequestWatchReactor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -500,15 +500,8 @@ export const make = Effect.gen(function* () {
],
{ concurrency: 2 },
);
// Activity failures must not cancel or hide a permanent detail failure.
// Activity is irrelevant once the pull request is closed or merged, so it cannot block ending.
const read = Exit.isFailure(detailRead)
? Exit.failCause(detailRead.cause)
: detailRead.value.state !== "open"
? Exit.succeed([detailRead.value, Option.none<PullRequestActivity>()] as const)
: Exit.isFailure(activityRead)
? Exit.failCause(activityRead.cause)
: Exit.succeed([detailRead.value, activityRead.value] as const);
// Comment availability must not suppress check results or a permanent detail failure.
const read = detailRead;
if (Exit.isFailure(read)) {
if (Cause.hasInterruptsOnly(read.cause)) return yield* Effect.failCause(read.cause);
lastReads.delete(group.key);
Expand All @@ -527,7 +520,10 @@ export const make = Effect.gen(function* () {
return yield* Effect.failCause(read.cause);
}
readFailures.delete(group.key);
const [detail, activity] = read.value;
const detail = read.value;
const activity = Exit.isSuccess(activityRead)
? activityRead.value
: Option.none<PullRequestActivity>();
for (const target of group.targets) {
const life = lifeOf(target);
const headSha = detail.headSha ?? life.headSha;
Expand All @@ -550,6 +546,15 @@ export const make = Effect.gen(function* () {
);
}

if (Exit.isFailure(activityRead)) {
if (Cause.hasInterruptsOnly(activityRead.cause))
return yield* Effect.failCause(activityRead.cause);
threadTails.delete(group.key);
yield* logFailure("pull request watch activity read failed", { pullRequest: group.key })(
activityRead.cause,
);
}

// Never advance the remark watermark past comments an incomplete read could have missed.
const remarks = Option.isSome(activity)
? yield* readRemarks(
Expand Down
18 changes: 11 additions & 7 deletions apps/server/src/orchestration-v2/runtimeLayer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4456,6 +4456,7 @@ it.layer(layerTest)("OrchestrationV2LayerLive lifecycle", (it) => {

const headSha = "6074dd48ff";
let checks: PullRequestDetail["checks"] = [];
let activityUnavailable = false;
const host = Layer.mergeAll(
NodeServices.layer,
NodeCrypto.layer,
Expand All @@ -4471,13 +4472,15 @@ it.layer(layerTest)("OrchestrationV2LayerLive lifecycle", (it) => {
checks,
})),
activity: () =>
Effect.succeed({
comments: [],
commentCount: 0,
commentsTruncated: false,
reviewThreads: [],
commits: [],
}),
activityUnavailable
? Effect.die("comments unavailable")
: Effect.succeed({
comments: [],
commentCount: 0,
commentsTruncated: false,
reviewThreads: [],
commits: [],
}),
}),
);
const wakes = Effect.map(
Expand All @@ -4504,6 +4507,7 @@ it.layer(layerTest)("OrchestrationV2LayerLive lifecycle", (it) => {
yield* sweep;
assert.lengthOf(yield* wakes, 1);

activityUnavailable = true;
checks = [{ name: "lint", status: "success", description: null, url: null, required: true }];
yield* TestClock.adjust("10 minutes");
yield* sweep;
Expand Down
Loading