doc2vec 2.10.4 → 2.10.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/database.js +79 -46
  2. package/package.json +1 -1
package/dist/database.js CHANGED
@@ -215,7 +215,13 @@ class DatabaseManager {
215
215
  }
216
216
  }
217
217
  catch (error) {
218
- logger.error(`Failed to update metadata value for ${key}:`, error);
218
+ // Best-effort by design: a failed metadata write errs toward the
219
+ // safe direction (redundant reprocessing next run — etag/lastmod/
220
+ // watermark stay behind, never skip ahead), so we warn rather than
221
+ // fail the job. Genuine disk/connection failures surface earlier at
222
+ // the chunk-write stage (storeChunkInQdrant), which shares this
223
+ // collection and throws.
224
+ logger.warn(`Failed to update metadata value for ${key} (continuing; will retry next run):`, error);
219
225
  }
220
226
  }
221
227
  static async getLastRunDate(dbConnection, repo, defaultDate, logger) {
@@ -436,7 +442,11 @@ class DatabaseManager {
436
442
  });
437
443
  }
438
444
  catch (error) {
439
- console.error("Error storing chunk in Qdrant:", error);
445
+ // Rethrow so the failure propagates to the top-level handler and the
446
+ // job exits non-zero. Swallowing here previously let a sync "succeed"
447
+ // while chunks silently failed to store (e.g. Qdrant disk full).
448
+ console.error(`Error storing chunk in Qdrant (collection ${collectionName}, url ${chunk.metadata.url}):`, error);
449
+ throw error;
440
450
  }
441
451
  }
442
452
  static removeObsoleteChunksSQLite(db, visitedUrls, urlPrefix, logger) {
@@ -518,7 +528,11 @@ class DatabaseManager {
518
528
  }
519
529
  }
520
530
  catch (error) {
531
+ // Rethrow so a failed cleanup fails the job instead of silently
532
+ // leaving orphans behind. This is idempotent and recomputed each
533
+ // run, so a rerun retries it cleanly.
521
534
  logger.error(`Error removing obsolete chunks from Qdrant:`, error);
535
+ throw error;
522
536
  }
523
537
  }
524
538
  static hasColumn(db, columnName) {
@@ -561,7 +575,12 @@ class DatabaseManager {
561
575
  logger.info(`Deleted chunks from Qdrant for URL ${url}`);
562
576
  }
563
577
  catch (error) {
578
+ // Rethrow so the failure propagates and the job exits non-zero.
579
+ // A swallowed delete leaves stale chunks behind while the sync
580
+ // reports success. Callers that treat deletion as best-effort
581
+ // (e.g. 404 cleanup) wrap this call in their own try/catch.
564
582
  logger.error(`Error deleting chunks from Qdrant for URL ${url}:`, error);
583
+ throw error;
565
584
  }
566
585
  }
567
586
  /**
@@ -726,53 +745,64 @@ class DatabaseManager {
726
745
  urlPrefix = `file://${cleanedDirPrefix}`;
727
746
  }
728
747
  logger.debug(`Checking for obsolete chunks with URL prefix: ${urlPrefix}`);
729
- const response = await client.scroll(collectionName, {
730
- limit: 10000,
731
- with_payload: true,
732
- with_vector: false,
733
- filter: {
734
- must: [
735
- {
736
- key: "url",
737
- match: {
738
- text: urlPrefix
739
- }
748
+ // Scroll through ALL matching points via next_page_offset. A single
749
+ // capped scroll would only examine the first page, so obsolete
750
+ // chunks beyond it (in collections larger than the page limit) would
751
+ // never be removed.
752
+ const filter = {
753
+ must: [
754
+ {
755
+ key: "url",
756
+ match: {
757
+ text: urlPrefix
740
758
  }
741
- ],
742
- must_not: [
743
- {
744
- key: "is_metadata",
745
- match: {
746
- value: true
747
- }
759
+ }
760
+ ],
761
+ must_not: [
762
+ {
763
+ key: "is_metadata",
764
+ match: {
765
+ value: true
748
766
  }
749
- ]
750
- }
751
- });
752
- const obsoletePointIds = response.points
753
- .filter((point) => {
754
- const url = point.payload?.url;
755
- // Double check it's not a metadata record
756
- if (point.payload?.is_metadata === true) {
757
- return false;
758
- }
759
- if (!url || !url.startsWith(urlPrefix)) {
760
- return false;
761
- }
762
- let filePath;
763
- if (isRewriteMode) {
764
- // URL rewrite mode: extract relative path and construct full file path
765
- const config = pathConfig;
766
- const relativePath = url.substring(urlPrefix.length + 1); // +1 for the '/'
767
- filePath = path.join(config.path, relativePath);
768
- }
769
- else {
770
- // Direct file path mode: remove file:// prefix to match with processedFiles
771
- filePath = url.startsWith('file://') ? url.substring(7) : '';
767
+ }
768
+ ]
769
+ };
770
+ const obsoletePointIds = [];
771
+ let offset = undefined;
772
+ do {
773
+ const response = await client.scroll(collectionName, {
774
+ limit: 1000,
775
+ offset,
776
+ with_payload: true,
777
+ with_vector: false,
778
+ filter
779
+ });
780
+ for (const point of response.points) {
781
+ const url = point.payload?.url;
782
+ // Double check it's not a metadata record
783
+ if (point.payload?.is_metadata === true) {
784
+ continue;
785
+ }
786
+ if (!url || !url.startsWith(urlPrefix)) {
787
+ continue;
788
+ }
789
+ let filePath;
790
+ if (isRewriteMode) {
791
+ // URL rewrite mode: extract relative path and construct full file path
792
+ const config = pathConfig;
793
+ const relativePath = url.substring(urlPrefix.length + 1); // +1 for the '/'
794
+ filePath = path.join(config.path, relativePath);
795
+ }
796
+ else {
797
+ // Direct file path mode: remove file:// prefix to match with processedFiles
798
+ filePath = url.startsWith('file://') ? url.substring(7) : '';
799
+ }
800
+ if (filePath && !processedFiles.has(filePath)) {
801
+ obsoletePointIds.push(point.id);
802
+ }
772
803
  }
773
- return filePath && !processedFiles.has(filePath);
774
- })
775
- .map((point) => point.id);
804
+ offset = response.next_page_offset;
805
+ } while (offset !== null && offset !== undefined);
776
806
  if (obsoletePointIds.length > 0) {
777
807
  await client.delete(collectionName, {
778
808
  points: obsoletePointIds,
@@ -784,7 +814,10 @@ class DatabaseManager {
784
814
  }
785
815
  }
786
816
  catch (error) {
817
+ // Rethrow so a failed cleanup fails the job instead of silently
818
+ // leaving orphans behind (idempotent — retried cleanly next run).
787
819
  logger.error(`Error removing obsolete chunks from Qdrant:`, error);
820
+ throw error;
788
821
  }
789
822
  }
790
823
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doc2vec",
3
- "version": "2.10.4",
3
+ "version": "2.10.5",
4
4
  "type": "commonjs",
5
5
  "description": "",
6
6
  "main": "dist/doc2vec.js",