A push stopped by a deploy while it unpacks is retried too (#194)
* A push stopped by a deploy while it unpacks or stores is retried too
- CI / Typecheck and bundleFailed
- CI / Unit tests (1/2)Failed
- CI / Unit tests (2/2)Failed
- End-to-end / End-to-end (agent reviews, tasks, Today)Failed
- End-to-end / End-to-end (git, PRs, Actions)Failed
- End-to-end / End-to-end (large pushes)Failed
- End-to-end / End-to-end (passkeys, registry, email)Failed
- End-to-end / End-to-end (real histories)Failed
- End-to-end / End-to-end (security)Failed
- Live test / Containers, registry, sandboxes, webhooks, schedules, LFS and pull requestssuccess
3 files changed+10−2
modifiedapps/diffinery/src/git/protocol.ts+3−0View file
| @@ -289,6 +289,9 @@ | ||
| 289 | 289 | reason?: string; |
| 290 | 290 | } |
| 291 | 291 | |
| 292 | +/** The platform's error for a Durable Object stopped by a new version of its code. */ | |
| 293 | +export const resetByDeploy = (e: unknown) => e instanceof Error && /durable object reset because its code was updated/i.test(e.message); | |
| 294 | + | |
| 292 | 295 | /** |
| 293 | 296 | * The unpack status for a push that couldn't be unpacked or stored. Running out of memory says to |
| 294 | 297 | * split the push, the wording clients (and the GitHub importer, which then pushes smaller chunks) |
modifiedapps/diffinery/src/http/git.ts+2−2View file
| @@ -7,6 +7,7 @@ | ||
| 7 | 7 | import { importPushAllowed } from "../imports/service.js"; |
| 8 | 8 | import { loadRepo, repoStub } from "./common.js"; |
| 9 | 9 | import type { Caller } from "../repo/types.js"; |
| 10 | +import { resetByDeploy } from "../git/protocol.js"; | |
| 10 | 11 | |
| 11 | 12 | /** |
| 12 | 13 | * Git smart HTTP (protocol v2 for fetch/clone, v0 for push) and the Git LFS |
| @@ -80,8 +81,7 @@ | ||
| 80 | 81 | |
| 81 | 82 | const PUSH_TRIES = 2; |
| 82 | 83 | |
| 83 | -/** The platform's error for a Durable Object stopped by a new version of its code. */ | |
| 84 | -export const resetByDeploy = (e: unknown) => e instanceof Error && /durable object reset because its code was updated/i.test(e.message); | |
| 84 | +export { resetByDeploy }; | |
| 85 | 85 | |
| 86 | 86 | /** A fetch's wants and haves; git's own negotiation stays far below this. */ |
| 87 | 87 | const MAX_UPLOAD_PACK_REQUEST = 16 * 1024 * 1024; |
modifiedapps/diffinery/src/repo/RepoDO.ts+5−0View file
| @@ -44,6 +44,7 @@ | ||
| 44 | 44 | parseReceivePack, |
| 45 | 45 | reportStatus, |
| 46 | 46 | type ReceiveRequest, |
| 47 | + resetByDeploy, | |
| 47 | 48 | unpackFailure, |
| 48 | 49 | type RefEntry, |
| 49 | 50 | type RefResult, |
| @@ -576,6 +577,8 @@ | ||
| 576 | 577 | req = head.req; |
| 577 | 578 | packAt = head.packOffset; |
| 578 | 579 | } catch (e) { |
| 580 | + // A deploy that stops this object mid-push is the Worker's to retry (http/git.ts receiveWithRetry). | |
| 581 | + if (resetByDeploy(e)) throw e; | |
| 579 | 582 | return reportStatus({ commands: [], capabilities: new Set<string>(), pushOptions: [], pack: null }, unpackFailure(e), []); |
| 580 | 583 | } |
| 581 | 584 | } |
| @@ -613,6 +616,7 @@ | ||
| 613 | 616 | ); |
| 614 | 617 | } |
| 615 | 618 | } catch (e) { |
| 619 | + if (resetByDeploy(e)) throw e; | |
| 616 | 620 | unpackError = unpackFailure(e); |
| 617 | 621 | } |
| 618 | 622 | const results: RefResult[] = []; |
| @@ -664,6 +668,7 @@ | ||
| 664 | 668 | try { |
| 665 | 669 | await contents.write(); |
| 666 | 670 | } catch (e) { |
| 671 | + if (resetByDeploy(e)) throw e; | |
| 667 | 672 | for (const c of req.commands) results.push({ ref: c.ref, ok: false, reason: "unpacker error" }); |
| 668 | 673 | return reportStatus(req, unpackFailure(e), results); |
| 669 | 674 | } |