(
live: LiveShellRun,
patch: PersistPatch = {},
options: PersistOptions = {},
)
| 1112 | } |
| 1113 | |
| 1114 | private queuePersist( |
| 1115 | live: LiveShellRun, |
| 1116 | patch: PersistPatch = {}, |
| 1117 | options: PersistOptions = {}, |
| 1118 | ): Promise<ShellRunRecord> { |
| 1119 | const barrier = options.snapshotBarrier |
| 1120 | ? options.snapshotBarrier |
| 1121 | : this.snapshotAtCut(live, Boolean(options.allowLastGood)); |
| 1122 | let failureStage: 'snapshot' | 'persist' = 'snapshot'; |
| 1123 | const settledBarrier = barrier.then( |
| 1124 | (snapshot) => ({ ok: true as const, snapshot }), |
| 1125 | (error: unknown) => ({ ok: false as const, error }), |
| 1126 | ); |
| 1127 | const task = live.persistChain.then(async () => { |
| 1128 | const settled = await settledBarrier; |
| 1129 | if (!settled.ok) throw settled.error; |
| 1130 | const { snapshot } = settled; |
| 1131 | if (!snapshot) { |
| 1132 | if (this.currentGeneration(live) > live.lastPersistedGeneration) { |
| 1133 | this.scheduleAutomaticFlush(live); |
| 1134 | } |
| 1135 | return live.record; |
| 1136 | } |
| 1137 | failureStage = 'persist'; |
| 1138 | if (live.persistFailure && !options.bestEffort) throw live.persistFailure; |
| 1139 | const current = live.record; |
| 1140 | const candidate: ShellRunRecord = { ...current, ...patch, output: snapshot.output }; |
| 1141 | let updated = current; |
| 1142 | if (!isDeepStrictEqual(candidate, current)) { |
| 1143 | updated = await this.input.store.updateShellRun(live.sessionId, live.shellRunId, { |
| 1144 | ...patch, |
| 1145 | output: snapshot.output, |
| 1146 | updatedAt: this.input.now(), |
| 1147 | }); |
| 1148 | live.record = updated; |
| 1149 | if (live.visibleRef) this.notifyShellRunUpdate(updated); |
| 1150 | } |
| 1151 | live.lastPersistedGeneration = Math.max(live.lastPersistedGeneration, snapshot.generation); |
| 1152 | live.lastSnapshotWallTime = Date.now(); |
| 1153 | return updated; |
| 1154 | }); |
| 1155 | live.persistChain = task.then( |
| 1156 | () => undefined, |
| 1157 | (error: unknown) => { |
| 1158 | const failure = asError( |
| 1159 | error, |
| 1160 | failureStage === 'snapshot' ? 'ShellRun snapshot failed' : 'ShellRun persistence failed', |
| 1161 | ); |
| 1162 | if (failureStage === 'persist') live.persistFailure ??= failure; |
| 1163 | this.handleIntegrityFailure(live, failure); |
| 1164 | }, |
| 1165 | ); |
| 1166 | return task; |
| 1167 | } |
| 1168 | |
| 1169 | private snapshotAtCut(live: LiveShellRun, allowLastGood: boolean): Promise<SnapshotAtCut> { |
| 1170 | if (live.mode === 'pipes') { |
no test coverage detected