fix: preserve batch failure state across EmbeddingService recreations
- Add transferBatchState() method to EmbeddingService to preserve failure tracking when the service is recreated during reindex operations - Update manager.createEmbeddingService() to transfer state by default - Skip state transfer when switching to fallback provider (fresh start) - Add mock rateLimiter to send.test.ts to fix test failures - Add error handling in audit-log.ts for ENOENT during test cleanup Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
9dd38535e4
commit
3034accd75
@ -45,6 +45,11 @@ vi.mock("../../config/sessions.js", async () => {
|
||||
const makeContext = (): GatewayRequestContext =>
|
||||
({
|
||||
dedupe: new Map(),
|
||||
rateLimiter: {
|
||||
checkChannelMessage: () => ({ allowed: true }),
|
||||
checkRequest: () => ({ allowed: true }),
|
||||
recordAuthFailure: () => {},
|
||||
},
|
||||
}) as unknown as GatewayRequestContext;
|
||||
|
||||
describe("gateway send mirroring", () => {
|
||||
|
||||
@ -122,6 +122,20 @@ export class EmbeddingService {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer batch failure state from another EmbeddingService instance.
|
||||
* Used when recreating the service to preserve failure tracking across reindexes.
|
||||
*/
|
||||
transferBatchState(from: EmbeddingService): void {
|
||||
this.batchFailureCount = from.batchFailureCount;
|
||||
this.batchFailureLastError = from.batchFailureLastError;
|
||||
this.batchFailureLastProvider = from.batchFailureLastProvider;
|
||||
// Also transfer disabled state if the source had batch disabled due to failures
|
||||
if (!from.batch.enabled && from.batchFailureCount >= BATCH_FAILURE_LIMIT) {
|
||||
this.batch.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache entry count.
|
||||
*/
|
||||
|
||||
@ -1156,7 +1156,7 @@ export class MemoryIndexManager {
|
||||
return /embedding|embeddings|batch/i.test(message);
|
||||
}
|
||||
|
||||
private createEmbeddingService(): EmbeddingService {
|
||||
private createEmbeddingService(preserveBatchState = true): EmbeddingService {
|
||||
const batch = this.settings.remote?.batch;
|
||||
const enabled = Boolean(
|
||||
batch?.enabled &&
|
||||
@ -1178,7 +1178,12 @@ export class MemoryIndexManager {
|
||||
},
|
||||
agentId: this.agentId,
|
||||
};
|
||||
return new EmbeddingService(this.db, config);
|
||||
const service = new EmbeddingService(this.db, config);
|
||||
// Preserve batch failure state across service recreations (e.g., during reindex)
|
||||
if (preserveBatchState && this.embeddingService) {
|
||||
service.transferBatchState(this.embeddingService);
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
private async activateFallbackProvider(reason: string): Promise<boolean> {
|
||||
@ -1210,7 +1215,8 @@ export class MemoryIndexManager {
|
||||
this.openAi = fallbackResult.openAi;
|
||||
this.gemini = fallbackResult.gemini;
|
||||
this.providerKey = this.computeProviderKey();
|
||||
this.embeddingService = this.createEmbeddingService();
|
||||
// Don't preserve batch state when switching providers - start fresh with new provider
|
||||
this.embeddingService = this.createEmbeddingService(false);
|
||||
log.warn(`memory embeddings: switched to fallback provider (${fallback})`, { reason });
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -110,14 +110,23 @@ function getArchivePath(basePath: string, date: Date): string {
|
||||
async function appendAuditEntry(entry: AuditLogEntry, baseDir?: string): Promise<void> {
|
||||
const { dir, currentPath } = resolveAuditPaths(baseDir);
|
||||
|
||||
// Ensure directory exists
|
||||
await fs.mkdir(dir, { recursive: true });
|
||||
try {
|
||||
// Ensure directory exists
|
||||
await fs.mkdir(dir, { recursive: true });
|
||||
|
||||
// Serialize entry
|
||||
const line = JSON.stringify(entry) + "\n";
|
||||
// Serialize entry
|
||||
const line = JSON.stringify(entry) + "\n";
|
||||
|
||||
// Append to file (create if doesn't exist)
|
||||
await fs.appendFile(currentPath, line, { encoding: "utf8", mode: 0o600 });
|
||||
// Append to file (create if doesn't exist)
|
||||
await fs.appendFile(currentPath, line, { encoding: "utf8", mode: 0o600 });
|
||||
} catch (err) {
|
||||
// Silently ignore errors if the directory was removed (e.g., during test cleanup)
|
||||
// This prevents unhandled rejections when the audit log is disabled or the path is invalid
|
||||
const code = (err as NodeJS.ErrnoException).code;
|
||||
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
Reference in New Issue
Block a user