























@@ -82,6 +82,7 @@ const FTS_TABLE = "chunks_fts";
8282const EMBEDDING_CACHE_TABLE = "embedding_cache";
8383const SESSION_DIRTY_DEBOUNCE_MS = 5000;
8484const SESSION_DELTA_READ_CHUNK_BYTES = 64 * 1024;
85+const SESSION_SYNC_YIELD_EVERY = 10;
8586const VECTOR_LOAD_TIMEOUT_MS = 30_000;
8687const IGNORED_MEMORY_WATCH_DIR_NAMES = new Set([
8788".git",
@@ -140,6 +141,18 @@ export function runDetachedMemorySync(sync: () => Promise<void>, reason: "interv
140141});
141142}
142143144+function createSessionSyncYield(total: number): () => Promise<void> {
145+let completed = 0;
146+return async () => {
147+completed += 1;
148+if (completed < total && completed % SESSION_SYNC_YIELD_EVERY === 0) {
149+await new Promise<void>((resolve) => {
150+setImmediate(resolve);
151+});
152+}
153+};
154+}
155+143156export abstract class MemoryManagerSyncOps {
144157protected abstract readonly cfg: OpenClawConfig;
145158protected abstract readonly agentId: string;
@@ -870,53 +883,58 @@ export abstract class MemoryManagerSyncOps {
870883});
871884}
872885886+const yieldAfterSessionFile = createSessionSyncYield(files.length);
873887const tasks = files.map((absPath) => async () => {
874-if (!indexAll && !this.sessionsDirtyFiles.has(absPath)) {
875-if (params.progress) {
876-params.progress.completed += 1;
877-params.progress.report({
878-completed: params.progress.completed,
879-total: params.progress.total,
880-});
888+try {
889+if (!indexAll && !this.sessionsDirtyFiles.has(absPath)) {
890+if (params.progress) {
891+params.progress.completed += 1;
892+params.progress.report({
893+completed: params.progress.completed,
894+total: params.progress.total,
895+});
896+}
897+return;
881898}
882-return;
883-}
884-const entry = await buildSessionEntry(absPath);
885-if (!entry) {
886-if (params.progress) {
887-params.progress.completed += 1;
888-params.progress.report({
889-completed: params.progress.completed,
890- total: params.progress.total,
891-});
899+const entry = await buildSessionEntry(absPath);
900+ if (!entry) {
901+ if (params.progress) {
902+ params.progress.completed += 1;
903+ params.progress.report({
904+ completed: params.progress.completed,
905+ total: params.progress.total,
906+});
907+}
908+return;
892909}
893-return;
894-}
895-const existingHash = resolveMemorySourceExistingHash({
896-db: this.db,
897-source: "sessions",
898-path: entry.path,
899- existingHashes,
900-});
901-if (!params.needsFullReindex && existingHash === entry.hash) {
910+const existingHash = resolveMemorySourceExistingHash({
911+db: this.db,
912+source: "sessions",
913+path: entry.path,
914+ existingHashes,
915+});
916+if (!params.needsFullReindex && existingHash === entry.hash) {
917+if (params.progress) {
918+params.progress.completed += 1;
919+params.progress.report({
920+completed: params.progress.completed,
921+total: params.progress.total,
922+});
923+}
924+this.resetSessionDelta(absPath, entry.size);
925+return;
926+}
927+await this.indexFile(entry, { source: "sessions", content: entry.content });
928+this.resetSessionDelta(absPath, entry.size);
902929if (params.progress) {
903930params.progress.completed += 1;
904931params.progress.report({
905932completed: params.progress.completed,
906933total: params.progress.total,
907934});
908935}
909-this.resetSessionDelta(absPath, entry.size);
910-return;
911-}
912-await this.indexFile(entry, { source: "sessions", content: entry.content });
913-this.resetSessionDelta(absPath, entry.size);
914-if (params.progress) {
915-params.progress.completed += 1;
916-params.progress.report({
917-completed: params.progress.completed,
918-total: params.progress.total,
919-});
936+} finally {
937+await yieldAfterSessionFile();
920938}
921939});
922940await runWithConcurrency(tasks, this.getIndexConcurrency());
@@ -927,25 +945,31 @@ export abstract class MemoryManagerSyncOps {
927945return;
928946}
929947930-for (const stale of existingRows ?? []) {
931-if (activePaths.has(stale.path)) {
932-continue;
933-}
934-deleteFileByPathAndSource.run(stale.path, "sessions");
935-if (deleteVectorRowsByPathAndSource) {
936-try {
937-deleteVectorRowsByPathAndSource.run(stale.path, "sessions");
938-} catch {}
939-}
940-deleteChunksByPathAndSource.run(stale.path, "sessions");
941-if (deleteFtsRowsByPathSourceAndModel) {
942-try {
943-deleteFtsRowsByPathSourceAndModel.run(
944-stale.path,
945-"sessions",
946-this.provider?.model ?? "fts-only",
947-);
948-} catch {}
948+const staleRows = existingRows ?? [];
949+const yieldAfterStaleSessionRow = createSessionSyncYield(staleRows.length);
950+for (const stale of staleRows) {
951+try {
952+if (activePaths.has(stale.path)) {
953+continue;
954+}
955+deleteFileByPathAndSource.run(stale.path, "sessions");
956+if (deleteVectorRowsByPathAndSource) {
957+try {
958+deleteVectorRowsByPathAndSource.run(stale.path, "sessions");
959+} catch {}
960+}
961+deleteChunksByPathAndSource.run(stale.path, "sessions");
962+if (deleteFtsRowsByPathSourceAndModel) {
963+try {
964+deleteFtsRowsByPathSourceAndModel.run(
965+stale.path,
966+"sessions",
967+this.provider?.model ?? "fts-only",
968+);
969+} catch {}
970+}
971+} finally {
972+await yieldAfterStaleSessionRow();
949973}
950974}
951975}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。