|
1 | 1 | import { onUnexpectedError } from '#/_base/errors/unexpectedError'; |
2 | 2 | import { Service } from '#/_base/di/service'; |
| 3 | +import { ILogService } from '#/_base/log/log'; |
3 | 4 | import { LifecycleScope } from '#/app/scopes'; |
4 | 5 | import { ScopeActivation, registerScopedService } from '#/_base/di/scope'; |
5 | 6 | import { IAgentBlobService } from '#/agent/blob/agentBlobService'; |
6 | 7 | import { IAgentScopeContext } from '#/agent/scopeContext/scopeContext'; |
| 8 | +import { ITelemetryService } from '#/app/telemetry/telemetry'; |
7 | 9 | import type { ContentPart } from '#/kosong/contract/message'; |
8 | | -import { IAppendLogStore } from '#/persistence/interface/appendLogStore'; |
9 | | -import { StorageError, StorageErrors } from '#/persistence/interface/storage'; |
| 10 | +import { |
| 11 | + type AppendLogTruncation, |
| 12 | + IAppendLogStore, |
| 13 | +} from '#/persistence/interface/appendLogStore'; |
| 14 | +import { IFileSystemStorageService, StorageError, StorageErrors } from '#/persistence/interface/storage'; |
10 | 15 |
|
11 | 16 | import { IWireService } from './wire'; |
12 | 17 | import { WireError, WireErrors } from './errors'; |
| 18 | +import { repairWireJournal } from './repair'; |
13 | 19 | import { |
14 | 20 | WIRE_PROTOCOL_VERSION, |
15 | 21 | isNewerWireVersion, |
@@ -38,14 +44,18 @@ export class WireService extends Service implements IWireService { |
38 | 44 | @IAgentScopeContext scopeContext: IAgentScopeContext, |
39 | 45 | @IAppendLogStore private readonly log: IAppendLogStore, |
40 | 46 | @IAgentBlobService private readonly blobService: IAgentBlobService, |
| 47 | + @IFileSystemStorageService private readonly storage: IFileSystemStorageService, |
| 48 | + @ILogService private readonly logger: ILogService, |
| 49 | + @ITelemetryService private readonly telemetry: ITelemetryService, |
41 | 50 | ) { |
42 | 51 | super(); |
43 | 52 | this.wireScope = scopeContext.scope(); |
44 | 53 | this._register(this.log.acquire(this.wireScope, AGENT_WIRE_RECORD_KEY)); |
45 | 54 | } |
46 | 55 |
|
47 | 56 | async seal(): Promise<void> { |
48 | | - for await (const record of this.log.read(this.wireScope, AGENT_WIRE_RECORD_KEY)) { |
| 57 | + const tolerate = { onTruncate: () => {} }; |
| 58 | + for await (const record of this.log.read(this.wireScope, AGENT_WIRE_RECORD_KEY, tolerate)) { |
49 | 59 | void record; |
50 | 60 | return; |
51 | 61 | } |
@@ -78,7 +88,12 @@ export class WireService extends Service implements IWireService { |
78 | 88 | } |
79 | 89 |
|
80 | 90 | async *readJournal(): AsyncIterable<WireRecord> { |
81 | | - const source = this.log.read<WireRecord>(this.wireScope, AGENT_WIRE_RECORD_KEY); |
| 91 | + let truncation: AppendLogTruncation | undefined; |
| 92 | + const source = this.log.read<WireRecord>(this.wireScope, AGENT_WIRE_RECORD_KEY, { |
| 93 | + onTruncate: (info) => { |
| 94 | + truncation = info; |
| 95 | + }, |
| 96 | + }); |
82 | 97 | let migrations: readonly WireMigration[] = []; |
83 | 98 | let rewrittenRecords: WireRecord[] | undefined; |
84 | 99 | let newerWireVersion = false; |
@@ -128,11 +143,42 @@ export class WireService extends Service implements IWireService { |
128 | 143 | if (!hasRecords) { |
129 | 144 | rewrittenRecords = [createWireMetadataRecord()]; |
130 | 145 | } |
131 | | - if (rewrittenRecords !== undefined) { |
| 146 | + if (truncation !== undefined) { |
| 147 | + await this.repairJournal(truncation, rewrittenRecords); |
| 148 | + } else if (rewrittenRecords !== undefined) { |
132 | 149 | await this.log.rewrite(this.wireScope, AGENT_WIRE_RECORD_KEY, rewrittenRecords); |
133 | 150 | } |
134 | 151 | } |
135 | 152 |
|
| 153 | + private async repairJournal( |
| 154 | + truncation: AppendLogTruncation, |
| 155 | + rewrittenRecords: WireRecord[] | undefined, |
| 156 | + ): Promise<void> { |
| 157 | + let records: WireRecord[] = rewrittenRecords ?? []; |
| 158 | + if (rewrittenRecords === undefined) { |
| 159 | + const tolerate = { onTruncate: () => {} }; |
| 160 | + for await (const record of this.log.read<WireRecord>( |
| 161 | + this.wireScope, |
| 162 | + AGENT_WIRE_RECORD_KEY, |
| 163 | + tolerate, |
| 164 | + )) { |
| 165 | + records.push(record); |
| 166 | + } |
| 167 | + } |
| 168 | + await repairWireJournal( |
| 169 | + { |
| 170 | + appendLog: this.log, |
| 171 | + storage: this.storage, |
| 172 | + log: this.logger, |
| 173 | + telemetry: this.telemetry, |
| 174 | + }, |
| 175 | + this.wireScope, |
| 176 | + AGENT_WIRE_RECORD_KEY, |
| 177 | + records, |
| 178 | + truncation, |
| 179 | + ); |
| 180 | + } |
| 181 | + |
136 | 182 | async flush(): Promise<void> { |
137 | 183 | await this.persistQueue; |
138 | 184 | await this.log.flush(); |
|
0 commit comments