mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-09-17 08:05:25 +02:00
fix: preserve removal intent when Redis enqueue fails
This commit is contained in:
+1
-1
@@ -203,7 +203,7 @@ export async function recoverStuckRemoving() {
|
|||||||
...serializeError(e),
|
...serializeError(e),
|
||||||
repoId: doc.repoId,
|
repoId: doc.repoId,
|
||||||
});
|
});
|
||||||
await markErrorIfRemoving(doc.repoId, "removal_interrupted");
|
// Keep REMOVING so another recovery pass can retry the enqueue.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -241,14 +241,9 @@ router.delete(
|
|||||||
const user = await getUser(req);
|
const user = await getUser(req);
|
||||||
isOwnerOrAdmin([repo.owner.id], user);
|
isOwnerOrAdmin([repo.owner.id], user);
|
||||||
await repo.updateStatus(RepositoryStatus.REMOVING);
|
await repo.updateStatus(RepositoryStatus.REMOVING);
|
||||||
try {
|
// Keep removal intent durable if Redis is unavailable. Recovery can
|
||||||
await addRemovalJob(repo.repoId);
|
// enqueue it later, and public requests must remain blocked meanwhile.
|
||||||
} catch (error) {
|
await addRemovalJob(repo.repoId);
|
||||||
const message =
|
|
||||||
error instanceof Error ? error.message : "removal_enqueue_failed";
|
|
||||||
await repo.updateStatus(RepositoryStatus.ERROR, message);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
return res.json({ status: repo.status });
|
return res.json({ status: repo.status });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error, res, req);
|
handleError(error, res, req);
|
||||||
|
|||||||
@@ -110,6 +110,44 @@ describe("removal recovery", function () {
|
|||||||
expect(added[1]).to.deep.equal({ repoId: repo.repoId });
|
expect(added[1]).to.deep.equal({ repoId: repo.repoId });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it("preserves deletion across a failed request enqueue and recovery enqueue", async function () {
|
||||||
|
const repo = new Repository(new AnonymizedRepositoryModel({
|
||||||
|
repoId: "repo-1", status: "ready",
|
||||||
|
owner: "507f1f77bcf86cd799439011",
|
||||||
|
options: { expirationMode: "never" }, source: {},
|
||||||
|
}));
|
||||||
|
routeUtils.getRepo = async () => repo;
|
||||||
|
routeUtils.getUser = async () => ({ model: { id: "admin" }, isAdmin: true });
|
||||||
|
let responseError;
|
||||||
|
routeUtils.handleError = (error) => { responseError = error; };
|
||||||
|
const failure = new Error("Redis unavailable");
|
||||||
|
queueModule.removeQueue = {
|
||||||
|
getJobs: async () => [],
|
||||||
|
getJob: async () => undefined,
|
||||||
|
add: async () => { throw failure; },
|
||||||
|
};
|
||||||
|
const router = require("../src/server/routes/repository-private").default;
|
||||||
|
const handler = router.stack.find((layer) =>
|
||||||
|
layer.route?.path === "/:repoId/" && layer.route.methods.delete
|
||||||
|
).route.stack[0].handle;
|
||||||
|
await handler({ params: { repoId: repo.repoId } }, {});
|
||||||
|
expect(responseError).to.equal(failure);
|
||||||
|
expect(repo.status).to.equal("removing");
|
||||||
|
let publicError;
|
||||||
|
try { await repo.check(); } catch (error) { publicError = error; }
|
||||||
|
expect(publicError.message).to.equal("repository_expired");
|
||||||
|
|
||||||
|
AnonymizedRepositoryModel.find = (filter) => ({
|
||||||
|
lean: async () => repo.status === filter.status ? [repo.model] : [],
|
||||||
|
});
|
||||||
|
await queueModule.recoverStuckRemoving();
|
||||||
|
expect(repo.status).to.equal("removing");
|
||||||
|
let added;
|
||||||
|
queueModule.removeQueue.add = async (...args) => { added = args; };
|
||||||
|
await queueModule.recoverStuckRemoving();
|
||||||
|
expect(added[1]).to.deep.equal({ repoId: repo.repoId });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("conference edits", function () {
|
describe("conference edits", function () {
|
||||||
|
|||||||
Reference in New Issue
Block a user