|
9 | 9 | decoratePlanWithStage, |
10 | 10 | discoverSourceManifest, |
11 | 11 | handleApiRequest, |
| 12 | + pruneAbandonedStageObjects, |
12 | 13 | pruneStaleLatestMacObjects, |
13 | 14 | reconcileSync, |
14 | 15 | uploadObjectToStage, |
@@ -46,51 +47,76 @@ export class SecondaryMirrorWorkflow extends WorkflowEntrypoint { |
46 | 47 | this.env, |
47 | 48 | ); |
48 | 49 |
|
49 | | - const uploadResults = []; |
50 | | - for (const item of plan.items) { |
51 | | - uploadResults.push( |
52 | | - await step.do(stepName("upload", item), UPLOAD_STEP, () => |
53 | | - nonRetryableGuard(() => |
54 | | - uploadObjectToStage(this.env, item, { |
55 | | - forceUpload: Boolean(payload.force), |
56 | | - }), |
| 50 | + const abandonedStageResult = await step.do( |
| 51 | + "prune abandoned secondary staging", |
| 52 | + HOUSEKEEPING_STEP, |
| 53 | + () => nonRetryableGuard(() => pruneAbandonedStageObjects(this.env, plan.stagePrefix)), |
| 54 | + ); |
| 55 | + |
| 56 | + try { |
| 57 | + const uploadResults = []; |
| 58 | + for (const item of plan.items) { |
| 59 | + uploadResults.push( |
| 60 | + await step.do(stepName("upload", item), UPLOAD_STEP, () => |
| 61 | + nonRetryableGuard(() => |
| 62 | + uploadObjectToStage(this.env, item, { |
| 63 | + forceUpload: Boolean(payload.force), |
| 64 | + }), |
| 65 | + ), |
57 | 66 | ), |
58 | | - ), |
59 | | - ); |
60 | | - } |
| 67 | + ); |
| 68 | + } |
61 | 69 |
|
62 | | - const commitResults = []; |
63 | | - for (const item of commitOrder(plan.items)) { |
64 | | - commitResults.push( |
65 | | - await step.do(stepName("commit", item), COMMIT_STEP, () => |
66 | | - nonRetryableGuard(() => commitObjectToAliases(this.env, item)), |
67 | | - ), |
68 | | - ); |
69 | | - } |
| 70 | + const commitResults = []; |
| 71 | + for (const item of commitOrder(plan.items)) { |
| 72 | + commitResults.push( |
| 73 | + await step.do(stepName("commit", item), COMMIT_STEP, () => |
| 74 | + nonRetryableGuard(() => commitObjectToAliases(this.env, item)), |
| 75 | + ), |
| 76 | + ); |
| 77 | + } |
70 | 78 |
|
71 | | - const staleAliasResult = await step.do("delete stale latest aliases", HOUSEKEEPING_STEP, () => |
72 | | - nonRetryableGuard(() => deleteStaleAliasObjects(this.env, plan.staleAliasKeys)), |
73 | | - ); |
| 79 | + const staleAliasResult = await step.do("delete stale latest aliases", HOUSEKEEPING_STEP, () => |
| 80 | + nonRetryableGuard(() => deleteStaleAliasObjects(this.env, plan.staleAliasKeys)), |
| 81 | + ); |
74 | 82 |
|
75 | | - const pruneResult = await step.do("prune stale Sparkle archives", HOUSEKEEPING_STEP, () => |
76 | | - nonRetryableGuard(() => pruneStaleLatestMacObjects(this.env, plan.keepLatestMacKeys)), |
77 | | - ); |
| 83 | + const pruneResult = await step.do("prune stale Sparkle archives", HOUSEKEEPING_STEP, () => |
| 84 | + nonRetryableGuard(() => pruneStaleLatestMacObjects(this.env, plan.keepLatestMacKeys)), |
| 85 | + ); |
78 | 86 |
|
79 | | - const cleanupResult = await step.do("cleanup secondary staging objects", HOUSEKEEPING_STEP, () => |
80 | | - nonRetryableGuard(() => cleanupStageObjects(this.env, plan.items)), |
81 | | - ); |
| 87 | + const cleanupResult = await step.do("cleanup secondary staging objects", HOUSEKEEPING_STEP, () => |
| 88 | + nonRetryableGuard(() => cleanupStageObjects(this.env, plan.items)), |
| 89 | + ); |
82 | 90 |
|
83 | | - return { |
84 | | - releaseTag: source.releaseTag, |
85 | | - manifestSha256: source.manifestSha256, |
86 | | - stagePrefix: plan.stagePrefix, |
87 | | - uploaded: uploadResults.length, |
88 | | - committed: commitResults.reduce((count, result) => count + result.aliases.length, 0), |
89 | | - staleAliasesDeleted: staleAliasResult.deleted.length, |
90 | | - pruned: pruneResult.pruned.length, |
91 | | - cleaned: cleanupResult.deleted.length, |
92 | | - completedAt: new Date().toISOString(), |
93 | | - }; |
| 91 | + return { |
| 92 | + releaseTag: source.releaseTag, |
| 93 | + manifestSha256: source.manifestSha256, |
| 94 | + stagePrefix: plan.stagePrefix, |
| 95 | + abandonedStageObjectsDeleted: abandonedStageResult.deleted.length, |
| 96 | + abandonedMultipartUploadsAborted: abandonedStageResult.aborted.length, |
| 97 | + uploaded: uploadResults.length, |
| 98 | + committed: commitResults.reduce((count, result) => count + result.aliases.length, 0), |
| 99 | + staleAliasesDeleted: staleAliasResult.deleted.length, |
| 100 | + pruned: pruneResult.pruned.length, |
| 101 | + cleaned: cleanupResult.deleted.length, |
| 102 | + completedAt: new Date().toISOString(), |
| 103 | + }; |
| 104 | + } catch (error) { |
| 105 | + try { |
| 106 | + await step.do("cleanup failed secondary staging objects", HOUSEKEEPING_STEP, () => |
| 107 | + nonRetryableGuard(() => cleanupStageObjects(this.env, plan.items)), |
| 108 | + ); |
| 109 | + } catch (cleanupError) { |
| 110 | + console.error( |
| 111 | + JSON.stringify({ |
| 112 | + event: "secondary_sync_failure_cleanup_failed", |
| 113 | + stagePrefix: plan.stagePrefix, |
| 114 | + error: cleanupError.message, |
| 115 | + }), |
| 116 | + ); |
| 117 | + } |
| 118 | + throw error; |
| 119 | + } |
94 | 120 | } |
95 | 121 | } |
96 | 122 |
|
|
0 commit comments