Skip to content

Commit 19bc08c

Browse files
committed
fix: resolve Qdrant connection errors during indexing (#5356)
- Add request timeout configuration (30s default) to QdrantClient - Implement retry logic with exponential backoff for socket errors - Add payload size-based chunking to prevent oversized requests (10MB limit) - Implement adaptive batch sizing in FileWatcher based on payload size - Add configuration options for Qdrant timeout settings - Update tests to handle new timeout parameter This fixes the 'SocketError: other side closed' issue that occurs when uploading large payloads (~150MB) to Qdrant during indexing.
1 parent a929935 commit 19bc08c

File tree

6 files changed

+313
-33
lines changed

6 files changed

+313
-33
lines changed

src/services/code-index/config-manager.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export class CodeIndexConfigManager {
2020
private qdrantUrl?: string = "http://localhost:6333"
2121
private qdrantApiKey?: string
2222
private searchMinScore?: number
23+
private _qdrantTimeout?: number
2324

2425
constructor(private readonly contextProxy: ContextProxy) {
2526
// Initialize with current configuration to avoid false restart triggers
@@ -358,13 +359,25 @@ export class CodeIndexConfigManager {
358359
return this.embedderProvider
359360
}
360361

362+
/**
363+
* Gets the Qdrant timeout configuration
364+
*/
365+
public get qdrantTimeout(): number {
366+
if (this._qdrantTimeout === undefined) {
367+
// Use a hardcoded default for now since we don't have a UI setting for this
368+
this._qdrantTimeout = 30000 // 30 seconds default
369+
}
370+
return this._qdrantTimeout
371+
}
372+
361373
/**
362374
* Gets the current Qdrant configuration
363375
*/
364-
public get qdrantConfig(): { url?: string; apiKey?: string } {
376+
public get qdrantConfig(): { url?: string; apiKey?: string; timeout?: number } {
365377
return {
366378
url: this.qdrantUrl,
367379
apiKey: this.qdrantApiKey,
380+
timeout: this.qdrantTimeout,
368381
}
369382
}
370383

src/services/code-index/constants/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,7 @@ export const BATCH_PROCESSING_CONCURRENCY = 10
2626

2727
/**Gemini Embedder */
2828
export const GEMINI_MAX_ITEM_TOKENS = 2048
29+
30+
/**Qdrant */
31+
export const MAX_PAYLOAD_SIZE_BYTES = 10 * 1024 * 1024 // 10MB per request
32+
export const QDRANT_REQUEST_TIMEOUT_MS = 30000 // 30 seconds

src/services/code-index/processors/file-watcher.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,13 @@ export class FileWatcher implements IFileWatcher {
319319
): Promise<Error | undefined> {
320320
if (pointsForBatchUpsert.length > 0 && this.vectorStore && !overallBatchError) {
321321
try {
322-
for (let i = 0; i < pointsForBatchUpsert.length; i += BATCH_SEGMENT_THRESHOLD) {
323-
const batch = pointsForBatchUpsert.slice(i, i + BATCH_SEGMENT_THRESHOLD)
322+
// Use adaptive batching based on payload size
323+
const estimatedSize = JSON.stringify(pointsForBatchUpsert).length
324+
const pointsPerMB = Math.max(1, Math.floor(pointsForBatchUpsert.length / (estimatedSize / 1024 / 1024)))
325+
const adaptiveBatchSize = Math.min(BATCH_SEGMENT_THRESHOLD, pointsPerMB * 5) // Target 5MB batches
326+
327+
for (let i = 0; i < pointsForBatchUpsert.length; i += adaptiveBatchSize) {
328+
const batch = pointsForBatchUpsert.slice(i, i + adaptiveBatchSize)
324329
let retryCount = 0
325330
let upsertError: Error | undefined
326331

src/services/code-index/service-factory.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,15 @@ export class CodeIndexServiceFactory {
108108
throw new Error("Qdrant URL missing for vector store creation")
109109
}
110110

111-
// Assuming constructor is updated: new QdrantVectorStore(workspacePath, url, vectorSize, apiKey?)
112-
return new QdrantVectorStore(this.workspacePath, config.qdrantUrl, vectorSize, config.qdrantApiKey)
111+
// Get the full qdrant config including timeout
112+
const qdrantConfig = this.configManager.qdrantConfig
113+
return new QdrantVectorStore(
114+
this.workspacePath,
115+
qdrantConfig.url!,
116+
vectorSize,
117+
qdrantConfig.apiKey,
118+
qdrantConfig.timeout,
119+
)
113120
}
114121

115122
/**

0 commit comments

Comments
 (0)