@powersync/service-module-mongodb-storage 0.0.0-dev-20260602073133 → 0.0.0-dev-20260803144812

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 (239) hide show
  1. package/CHANGELOG.md +101 -5
  2. package/dist/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.d.ts +3 -0
  3. package/dist/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.js +41 -0
  4. package/dist/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.js.map +1 -0
  5. package/dist/storage/MongoBucketStorage.d.ts +41 -16
  6. package/dist/storage/MongoBucketStorage.js +226 -71
  7. package/dist/storage/MongoBucketStorage.js.map +1 -1
  8. package/dist/storage/implementation/MongoBucketBatch.d.ts +56 -25
  9. package/dist/storage/implementation/MongoBucketBatch.js +110 -62
  10. package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
  11. package/dist/storage/implementation/MongoChecksums.d.ts +41 -13
  12. package/dist/storage/implementation/MongoChecksums.js +36 -121
  13. package/dist/storage/implementation/MongoChecksums.js.map +1 -1
  14. package/dist/storage/implementation/MongoCompactor.d.ts +17 -19
  15. package/dist/storage/implementation/MongoCompactor.js +80 -263
  16. package/dist/storage/implementation/MongoCompactor.js.map +1 -1
  17. package/dist/storage/implementation/MongoHydrationState.d.ts +11 -0
  18. package/dist/storage/implementation/MongoHydrationState.js +49 -0
  19. package/dist/storage/implementation/MongoHydrationState.js.map +1 -0
  20. package/dist/storage/implementation/MongoParameterCompactor.d.ts +7 -6
  21. package/dist/storage/implementation/MongoParameterCompactor.js +25 -2
  22. package/dist/storage/implementation/MongoParameterCompactor.js.map +1 -1
  23. package/dist/storage/implementation/MongoParsedSyncConfigSet.d.ts +13 -0
  24. package/dist/storage/implementation/MongoParsedSyncConfigSet.js +64 -0
  25. package/dist/storage/implementation/MongoParsedSyncConfigSet.js.map +1 -0
  26. package/dist/storage/implementation/MongoPersistedReplicationStream.d.ts +36 -0
  27. package/dist/storage/implementation/MongoPersistedReplicationStream.js +90 -0
  28. package/dist/storage/implementation/MongoPersistedReplicationStream.js.map +1 -0
  29. package/dist/storage/implementation/MongoPersistedSyncConfigContent.d.ts +25 -0
  30. package/dist/storage/implementation/MongoPersistedSyncConfigContent.js +123 -0
  31. package/dist/storage/implementation/MongoPersistedSyncConfigContent.js.map +1 -0
  32. package/dist/storage/implementation/MongoStorageProvider.js +39 -4
  33. package/dist/storage/implementation/MongoStorageProvider.js.map +1 -1
  34. package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +57 -29
  35. package/dist/storage/implementation/MongoSyncBucketStorage.js +87 -61
  36. package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
  37. package/dist/storage/implementation/MongoSyncRulesLock.d.ts +1 -1
  38. package/dist/storage/implementation/MongoSyncRulesLock.js +3 -3
  39. package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
  40. package/dist/storage/implementation/MongoWriteCheckpointAPI.d.ts +2 -1
  41. package/dist/storage/implementation/MongoWriteCheckpointAPI.js +171 -24
  42. package/dist/storage/implementation/MongoWriteCheckpointAPI.js.map +1 -1
  43. package/dist/storage/implementation/common/MongoSyncBucketStorageCheckpoint.d.ts +8 -0
  44. package/dist/storage/implementation/common/MongoSyncBucketStorageCheckpoint.js +2 -0
  45. package/dist/storage/implementation/common/MongoSyncBucketStorageCheckpoint.js.map +1 -0
  46. package/dist/storage/implementation/common/PersistedBatch.d.ts +7 -2
  47. package/dist/storage/implementation/common/PersistedBatch.js +12 -0
  48. package/dist/storage/implementation/common/PersistedBatch.js.map +1 -1
  49. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js +1 -1
  50. package/dist/storage/implementation/common/VersionedPowerSyncMongoBase.js.map +1 -1
  51. package/dist/storage/implementation/createMongoSyncBucketStorage.d.ts +2 -2
  52. package/dist/storage/implementation/createMongoSyncBucketStorage.js +4 -4
  53. package/dist/storage/implementation/createMongoSyncBucketStorage.js.map +1 -1
  54. package/dist/storage/implementation/db.js +17 -15
  55. package/dist/storage/implementation/db.js.map +1 -1
  56. package/dist/storage/implementation/models.d.ts +20 -13
  57. package/dist/storage/implementation/models.js.map +1 -1
  58. package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +9 -1
  59. package/dist/storage/implementation/v1/MongoBucketBatchV1.js +61 -29
  60. package/dist/storage/implementation/v1/MongoBucketBatchV1.js.map +1 -1
  61. package/dist/storage/implementation/v1/MongoChecksumsV1.d.ts +4 -4
  62. package/dist/storage/implementation/v1/MongoChecksumsV1.js +119 -7
  63. package/dist/storage/implementation/v1/MongoChecksumsV1.js.map +1 -1
  64. package/dist/storage/implementation/v1/MongoCompactorV1.d.ts +11 -2
  65. package/dist/storage/implementation/v1/MongoCompactorV1.js +251 -2
  66. package/dist/storage/implementation/v1/MongoCompactorV1.js.map +1 -1
  67. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.d.ts +18 -19
  68. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js +82 -58
  69. package/dist/storage/implementation/v1/MongoSyncBucketStorageV1.js.map +1 -1
  70. package/dist/storage/implementation/v1/SingleBucketStoreV1.d.ts +9 -10
  71. package/dist/storage/implementation/v1/SingleBucketStoreV1.js +2 -8
  72. package/dist/storage/implementation/v1/SingleBucketStoreV1.js.map +1 -1
  73. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.d.ts +2 -1
  74. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.js +3 -0
  75. package/dist/storage/implementation/v1/VersionedPowerSyncMongoV1.js.map +1 -1
  76. package/dist/storage/implementation/v1/models.d.ts +10 -1
  77. package/dist/storage/implementation/v3/BucketDataContextV3.d.ts +13 -0
  78. package/dist/storage/implementation/v3/BucketDataContextV3.js +23 -0
  79. package/dist/storage/implementation/v3/BucketDataContextV3.js.map +1 -0
  80. package/dist/storage/implementation/v3/MongoBucketBatchV3.d.ts +8 -4
  81. package/dist/storage/implementation/v3/MongoBucketBatchV3.js +309 -259
  82. package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -1
  83. package/dist/storage/implementation/v3/MongoChecksumsV3.d.ts +30 -9
  84. package/dist/storage/implementation/v3/MongoChecksumsV3.js +161 -20
  85. package/dist/storage/implementation/v3/MongoChecksumsV3.js.map +1 -1
  86. package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +40 -2
  87. package/dist/storage/implementation/v3/MongoCompactorV3.js +647 -23
  88. package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -1
  89. package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.d.ts +67 -0
  90. package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js +351 -0
  91. package/dist/storage/implementation/v3/MongoStoppedSyncConfigCleanup.js.map +1 -0
  92. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.d.ts +45 -30
  93. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js +272 -140
  94. package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js.map +1 -1
  95. package/dist/storage/implementation/v3/PersistedBatchV3.d.ts +6 -3
  96. package/dist/storage/implementation/v3/PersistedBatchV3.js +84 -21
  97. package/dist/storage/implementation/v3/PersistedBatchV3.js.map +1 -1
  98. package/dist/storage/implementation/v3/SourceRecordStoreV3.d.ts +3 -3
  99. package/dist/storage/implementation/v3/SourceRecordStoreV3.js +13 -11
  100. package/dist/storage/implementation/v3/SourceRecordStoreV3.js.map +1 -1
  101. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.d.ts +15 -13
  102. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js +32 -27
  103. package/dist/storage/implementation/v3/VersionedPowerSyncMongoV3.js.map +1 -1
  104. package/dist/storage/implementation/v3/bucket-format.d.ts +13 -0
  105. package/dist/storage/implementation/v3/bucket-format.js +77 -0
  106. package/dist/storage/implementation/v3/bucket-format.js.map +1 -0
  107. package/dist/storage/implementation/v3/chunking.d.ts +10 -0
  108. package/dist/storage/implementation/v3/chunking.js +30 -0
  109. package/dist/storage/implementation/v3/chunking.js.map +1 -0
  110. package/dist/storage/implementation/v3/models.d.ts +101 -21
  111. package/dist/storage/implementation/v3/models.js +11 -28
  112. package/dist/storage/implementation/v3/models.js.map +1 -1
  113. package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.d.ts +21 -0
  114. package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js +44 -0
  115. package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js.map +1 -0
  116. package/dist/storage/implementation/v3/object-storage/ObjectStorage.d.ts +30 -0
  117. package/dist/storage/implementation/v3/object-storage/ObjectStorage.js +12 -0
  118. package/dist/storage/implementation/v3/object-storage/ObjectStorage.js.map +1 -0
  119. package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.d.ts +70 -0
  120. package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js +146 -0
  121. package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js.map +1 -0
  122. package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.d.ts +42 -0
  123. package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js +285 -0
  124. package/dist/storage/implementation/v3/object-storage/S3ObjectStorage.js.map +1 -0
  125. package/dist/storage/implementation/v3/source-table-utils.d.ts +55 -0
  126. package/dist/storage/implementation/v3/source-table-utils.js +214 -0
  127. package/dist/storage/implementation/v3/source-table-utils.js.map +1 -0
  128. package/dist/storage/storage-index.d.ts +4 -4
  129. package/dist/storage/storage-index.js +4 -4
  130. package/dist/storage/storage-index.js.map +1 -1
  131. package/dist/types/types.d.ts +49 -3
  132. package/dist/types/types.js +48 -1
  133. package/dist/types/types.js.map +1 -1
  134. package/dist/utils/test-utils.d.ts +1 -2
  135. package/dist/utils/test-utils.js +7 -1
  136. package/dist/utils/test-utils.js.map +1 -1
  137. package/dist/utils/util.d.ts +9 -2
  138. package/dist/utils/util.js +128 -4
  139. package/dist/utils/util.js.map +1 -1
  140. package/package.json +12 -19
  141. package/src/migrations/db/migrations/1782950400000-checkpoint-requested-at-index.ts +55 -0
  142. package/src/storage/MongoBucketStorage.ts +347 -88
  143. package/src/storage/implementation/MongoBucketBatch.ts +147 -82
  144. package/src/storage/implementation/MongoChecksums.ts +93 -153
  145. package/src/storage/implementation/MongoCompactor.ts +102 -316
  146. package/src/storage/implementation/MongoHydrationState.ts +61 -0
  147. package/src/storage/implementation/MongoParameterCompactor.ts +25 -6
  148. package/src/storage/implementation/MongoParsedSyncConfigSet.ts +88 -0
  149. package/src/storage/implementation/MongoPersistedReplicationStream.ts +118 -0
  150. package/src/storage/implementation/MongoPersistedSyncConfigContent.ts +154 -0
  151. package/src/storage/implementation/MongoStorageProvider.ts +46 -4
  152. package/src/storage/implementation/MongoSyncBucketStorage.ts +121 -87
  153. package/src/storage/implementation/MongoSyncRulesLock.ts +7 -4
  154. package/src/storage/implementation/MongoWriteCheckpointAPI.ts +202 -28
  155. package/src/storage/implementation/common/MongoSyncBucketStorageCheckpoint.ts +9 -0
  156. package/src/storage/implementation/common/PersistedBatch.ts +19 -3
  157. package/src/storage/implementation/common/VersionedPowerSyncMongoBase.ts +1 -1
  158. package/src/storage/implementation/createMongoSyncBucketStorage.ts +21 -7
  159. package/src/storage/implementation/db.ts +19 -20
  160. package/src/storage/implementation/models.ts +20 -14
  161. package/src/storage/implementation/v1/MongoBucketBatchV1.ts +75 -37
  162. package/src/storage/implementation/v1/MongoChecksumsV1.ts +154 -12
  163. package/src/storage/implementation/v1/MongoCompactorV1.ts +294 -9
  164. package/src/storage/implementation/v1/MongoSyncBucketStorageV1.ts +142 -105
  165. package/src/storage/implementation/v1/SingleBucketStoreV1.ts +18 -27
  166. package/src/storage/implementation/v1/VersionedPowerSyncMongoV1.ts +11 -1
  167. package/src/storage/implementation/v1/models.ts +11 -1
  168. package/src/storage/implementation/v3/BucketDataContextV3.ts +32 -0
  169. package/src/storage/implementation/v3/MongoBucketBatchV3.ts +382 -321
  170. package/src/storage/implementation/v3/MongoChecksumsV3.ts +250 -32
  171. package/src/storage/implementation/v3/MongoCompactorV3.ts +847 -32
  172. package/src/storage/implementation/v3/MongoStoppedSyncConfigCleanup.ts +482 -0
  173. package/src/storage/implementation/v3/MongoSyncBucketStorageV3.ts +359 -187
  174. package/src/storage/implementation/v3/PersistedBatchV3.ts +118 -37
  175. package/src/storage/implementation/v3/SourceRecordStoreV3.ts +12 -12
  176. package/src/storage/implementation/v3/VersionedPowerSyncMongoV3.ts +46 -36
  177. package/src/storage/implementation/v3/bucket-format.ts +97 -0
  178. package/src/storage/implementation/v3/chunking.ts +40 -0
  179. package/src/storage/implementation/v3/models.ts +132 -55
  180. package/src/storage/implementation/v3/object-storage/BucketDataObjectStorage.ts +54 -0
  181. package/src/storage/implementation/v3/object-storage/ObjectStorage.ts +29 -0
  182. package/src/storage/implementation/v3/object-storage/ObjectStorageLifecycle.ts +171 -0
  183. package/src/storage/implementation/v3/object-storage/S3ObjectStorage.ts +343 -0
  184. package/src/storage/implementation/v3/source-table-utils.ts +392 -0
  185. package/src/storage/storage-index.ts +12 -4
  186. package/src/types/types.ts +58 -1
  187. package/src/utils/test-utils.ts +8 -3
  188. package/src/utils/util.ts +185 -6
  189. package/test/src/__snapshots__/storage.test.ts.snap +0 -75
  190. package/test/src/__snapshots__/storage_sync.test.ts.snap +35 -617
  191. package/test/src/cleanup-stopped-sync-configs.test.ts +671 -0
  192. package/test/src/helpers/MemoryObjectStorage.ts +53 -0
  193. package/test/src/helpers/s3TestFactory.ts +69 -0
  194. package/test/src/object_storage_lifecycle.test.ts +59 -0
  195. package/test/src/setup.ts +6 -1
  196. package/test/src/storage.test.ts +227 -13
  197. package/test/src/storage_compacting.test.ts +1951 -12
  198. package/test/src/storage_object_storage_inline_threshold.test.ts +116 -0
  199. package/test/src/storage_s3_checksums.test.ts +191 -0
  200. package/test/src/storage_s3_compaction_lifecycle.test.ts +417 -0
  201. package/test/src/storage_s3_reading.test.ts +526 -0
  202. package/test/src/storage_s3_writing.test.ts +135 -0
  203. package/test/src/storage_sync.test.ts +1180 -73
  204. package/test/src/storeCurrentData.test.ts +227 -0
  205. package/test/src/util.ts +2 -1
  206. package/tsconfig.json +1 -4
  207. package/tsconfig.tsbuildinfo +1 -1
  208. package/dist/storage/implementation/BucketDefinitionMapping.d.ts +0 -15
  209. package/dist/storage/implementation/BucketDefinitionMapping.js +0 -58
  210. package/dist/storage/implementation/BucketDefinitionMapping.js.map +0 -1
  211. package/dist/storage/implementation/MongoPersistedSyncRules.d.ts +0 -14
  212. package/dist/storage/implementation/MongoPersistedSyncRules.js +0 -67
  213. package/dist/storage/implementation/MongoPersistedSyncRules.js.map +0 -1
  214. package/dist/storage/implementation/MongoPersistedSyncRulesContent.d.ts +0 -29
  215. package/dist/storage/implementation/MongoPersistedSyncRulesContent.js +0 -76
  216. package/dist/storage/implementation/MongoPersistedSyncRulesContent.js.map +0 -1
  217. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.d.ts +0 -13
  218. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.js +0 -2
  219. package/dist/storage/implementation/common/MongoSyncBucketStorageContext.js.map +0 -1
  220. package/dist/storage/implementation/common/SingleBucketStore.d.ts +0 -54
  221. package/dist/storage/implementation/common/SingleBucketStore.js +0 -3
  222. package/dist/storage/implementation/common/SingleBucketStore.js.map +0 -1
  223. package/dist/storage/implementation/v3/MongoParameterCompactorV3.d.ts +0 -9
  224. package/dist/storage/implementation/v3/MongoParameterCompactorV3.js +0 -18
  225. package/dist/storage/implementation/v3/MongoParameterCompactorV3.js.map +0 -1
  226. package/dist/storage/implementation/v3/MongoParameterLookupV3.d.ts +0 -4
  227. package/dist/storage/implementation/v3/MongoParameterLookupV3.js +0 -9
  228. package/dist/storage/implementation/v3/MongoParameterLookupV3.js.map +0 -1
  229. package/dist/storage/implementation/v3/SingleBucketStoreV3.d.ts +0 -18
  230. package/dist/storage/implementation/v3/SingleBucketStoreV3.js +0 -48
  231. package/dist/storage/implementation/v3/SingleBucketStoreV3.js.map +0 -1
  232. package/src/storage/implementation/BucketDefinitionMapping.ts +0 -75
  233. package/src/storage/implementation/MongoPersistedSyncRules.ts +0 -82
  234. package/src/storage/implementation/MongoPersistedSyncRulesContent.ts +0 -101
  235. package/src/storage/implementation/common/MongoSyncBucketStorageContext.ts +0 -15
  236. package/src/storage/implementation/common/SingleBucketStore.ts +0 -63
  237. package/src/storage/implementation/v3/MongoParameterCompactorV3.ts +0 -24
  238. package/src/storage/implementation/v3/MongoParameterLookupV3.ts +0 -11
  239. package/src/storage/implementation/v3/SingleBucketStoreV3.ts +0 -68
package/src/utils/util.ts CHANGED
@@ -1,14 +1,56 @@
1
1
  import * as lib_mongo from '@powersync/lib-service-mongodb';
2
2
  import { mongo } from '@powersync/lib-service-mongodb';
3
- import { ReplicationAbortedError, ServiceAssertionError } from '@powersync/lib-services-framework';
3
+ import { Logger, ReplicationAbortedError, ServiceAssertionError } from '@powersync/lib-services-framework';
4
4
  import { storage, utils } from '@powersync/service-core';
5
5
  import * as bson from 'bson';
6
6
  import * as crypto from 'crypto';
7
7
  import * as timers from 'node:timers/promises';
8
8
  import * as uuid from 'uuid';
9
9
  import { BucketDataDoc } from '../storage/implementation/common/BucketDataDoc.js';
10
+ import { DEFAULT_CLEAR_BATCH_THROTTLE_RATE } from '../types/types.js';
10
11
 
11
- export function idPrefixFilter<T>(prefix: Partial<T>, rest: (keyof T)[]): mongo.Condition<T> {
12
+ /**
13
+ * Default and max batch size for clearing.
14
+ */
15
+ const CLEAR_BATCH_SIZE = 10_000;
16
+
17
+ /**
18
+ * Minimum batch size for clearing when a batch takes too long.
19
+ */
20
+ const CLEAR_MIN_BATCH_SIZE = 100;
21
+
22
+ /**
23
+ * We target batch duration to stay between the min and max. If the druation is outside this range,
24
+ * we increase or decrease the batch size.
25
+ *
26
+ * MONGO_CLEAR_OPERATION_TIMEOUT_MS controls the absolute max of individual find and delete operations,
27
+ * but we try to avoid hitting that.
28
+ */
29
+ const CLEAR_BATCH_MIN_DURATION_MS = 500;
30
+ const CLEAR_BATCH_MAX_DURATION_MS = 2000;
31
+
32
+ type ClearCollectionFilter<T extends mongo.Document> = mongo.Filter<T> & {
33
+ _id: mongo.FilterOperators<mongo.InferIdType<T>>;
34
+ };
35
+
36
+ function throwIfClearAborted(signal?: AbortSignal): void {
37
+ if (signal?.aborted) {
38
+ throw new ReplicationAbortedError('Aborted clearing data', signal.reason);
39
+ }
40
+ }
41
+
42
+ async function waitWithSignal(delayMs: number, signal: AbortSignal | undefined, abortMessage: string): Promise<void> {
43
+ try {
44
+ await timers.setTimeout(delayMs, undefined, { signal });
45
+ } catch (error) {
46
+ if (signal?.aborted) {
47
+ throw new ReplicationAbortedError(abortMessage, signal.reason);
48
+ }
49
+ throw error;
50
+ }
51
+ }
52
+
53
+ export function idPrefixFilter<T>(prefix: Partial<T>, rest: (keyof T)[]): mongo.FilterOperators<T> {
12
54
  let filter = {
13
55
  $gte: {
14
56
  ...prefix
@@ -26,9 +68,9 @@ export function idPrefixFilter<T>(prefix: Partial<T>, rest: (keyof T)[]): mongo.
26
68
  return filter;
27
69
  }
28
70
 
29
- export function generateSlotName(prefix: string, sync_rules_id: number) {
71
+ export function generateReplicationStreamName(prefix: string, replicationStreamId: number) {
30
72
  const slot_suffix = crypto.randomBytes(2).toString('hex');
31
- return `${prefix}${sync_rules_id}_${slot_suffix}`;
73
+ return `${prefix}${replicationStreamId}_${slot_suffix}`;
32
74
  }
33
75
 
34
76
  /**
@@ -141,6 +183,7 @@ export async function retryOnMongoMaxTimeMSExpired<T>(
141
183
  }
142
184
  ): Promise<T> {
143
185
  let retryCount = 0;
186
+ // Retry indefinitely on MaxTimeMSExpired errors with exponential backoff.
144
187
  while (true) {
145
188
  if (options.signal?.aborted) {
146
189
  throw new ReplicationAbortedError(options.abortMessage ?? 'Aborted MongoDB operation', options.signal.reason);
@@ -148,16 +191,152 @@ export async function retryOnMongoMaxTimeMSExpired<T>(
148
191
  try {
149
192
  return await operation();
150
193
  } catch (e) {
151
- if (!lib_mongo.isMongoServerError(e) || e.codeName !== 'MaxTimeMSExpired') {
194
+ if (!lib_mongo.isMaxTimeMSExpiredError(e)) {
152
195
  throw e;
153
196
  }
154
197
  retryCount += 1;
155
198
  options.onRetry?.(retryCount);
156
- await timers.setTimeout(options.retryDelayMs);
199
+ await waitWithSignal(options.retryDelayMs, options.signal, options.abortMessage ?? 'Aborted MongoDB operation');
200
+ }
201
+ }
202
+ }
203
+
204
+ async function clearCollectionInBatches(
205
+ logger: Logger,
206
+ label: string,
207
+ findAndDeleteBatch: (batchSize: number) => Promise<number>,
208
+ signal?: AbortSignal,
209
+ throttleRate = DEFAULT_CLEAR_BATCH_THROTTLE_RATE
210
+ ): Promise<number> {
211
+ let batchSize = CLEAR_BATCH_SIZE;
212
+ let deletedCount = 0;
213
+ while (true) {
214
+ throwIfClearAborted(signal);
215
+ try {
216
+ const batchStartedAt = performance.now();
217
+ const foundBatchSize = await findAndDeleteBatch(batchSize);
218
+ const batchDurationMs = performance.now() - batchStartedAt;
219
+ deletedCount += foundBatchSize;
220
+ if (foundBatchSize > 0) {
221
+ logger.info(
222
+ `Cleared batch of ${label} (${foundBatchSize} documents) in ${Math.round(batchDurationMs)}ms, continuing...`
223
+ );
224
+ }
225
+ if (foundBatchSize < batchSize) {
226
+ return deletedCount;
227
+ }
228
+ if (batchDurationMs > CLEAR_BATCH_MAX_DURATION_MS) {
229
+ batchSize = Math.max(CLEAR_MIN_BATCH_SIZE, Math.floor(batchSize / 2));
230
+ } else if (batchDurationMs < CLEAR_BATCH_MIN_DURATION_MS) {
231
+ batchSize = Math.min(CLEAR_BATCH_SIZE, batchSize * 2);
232
+ }
233
+ await waitWithSignal(batchDurationMs * throttleRate, signal, 'Aborted clearing data');
234
+ } catch (error) {
235
+ if (!lib_mongo.isTimeoutError(error) || batchSize == CLEAR_MIN_BATCH_SIZE) {
236
+ throw error;
237
+ }
238
+ const nextBatchSize = Math.max(CLEAR_MIN_BATCH_SIZE, Math.floor(batchSize / 2));
239
+ logger.info(
240
+ `Clearing batch of ${label} timed out with batch size ${batchSize}, retrying find and delete with ${nextBatchSize}...`
241
+ );
242
+ batchSize = nextBatchSize;
243
+
244
+ // Pause for at least the equivalent of one query timeout before retrying, since the cause may be high database load.
245
+ const pauseDuration = Math.max(throttleRate, 1.0) * lib_mongo.MONGO_CLEAR_OPERATION_TIMEOUT_MS;
246
+ await waitWithSignal(pauseDuration, signal, 'Aborted clearing data');
157
247
  }
158
248
  }
159
249
  }
160
250
 
251
+ export async function clearCollectionInIdRanges<T extends mongo.Document>(
252
+ logger: Logger,
253
+ label: string,
254
+ collection: mongo.Collection<T>,
255
+ filter: ClearCollectionFilter<T>,
256
+ signal?: AbortSignal,
257
+ throttleRate = DEFAULT_CLEAR_BATCH_THROTTLE_RATE
258
+ ): Promise<number> {
259
+ return clearCollectionInBatches(
260
+ logger,
261
+ label,
262
+ async (batchSize) => {
263
+ const queryOptions: mongo.FindOptions<T> = {
264
+ maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS,
265
+ projection: { _id: 1 }
266
+ };
267
+ const [batchEnd] = await collection
268
+ .find(filter, queryOptions)
269
+ .sort({ _id: 1 })
270
+ .skip(batchSize)
271
+ .limit(1)
272
+ .toArray();
273
+ throwIfClearAborted(signal);
274
+
275
+ if (batchEnd == null) {
276
+ // We're on the last batch
277
+ const result = await collection.deleteMany(filter, {
278
+ maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS
279
+ });
280
+ return result.deletedCount;
281
+ }
282
+
283
+ const idRange: mongo.FilterOperators<mongo.InferIdType<T>> = {
284
+ ...filter._id,
285
+ $lt: batchEnd._id
286
+ };
287
+ await collection.deleteMany(
288
+ {
289
+ ...filter,
290
+ _id: idRange
291
+ } as mongo.Filter<T>,
292
+ { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
293
+ );
294
+ return batchSize;
295
+ },
296
+ signal,
297
+ throttleRate
298
+ );
299
+ }
300
+
301
+ export async function clearCollectionInIdBatches<T extends mongo.Document>(
302
+ logger: Logger,
303
+ label: string,
304
+ collection: mongo.Collection<T>,
305
+ filter: mongo.Filter<T>,
306
+ signal?: AbortSignal,
307
+ throttleRate = DEFAULT_CLEAR_BATCH_THROTTLE_RATE
308
+ ): Promise<number> {
309
+ return clearCollectionInBatches(
310
+ logger,
311
+ label,
312
+ async (batchSize) => {
313
+ const documents = await collection
314
+ .find(filter, {
315
+ maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS,
316
+ projection: { _id: 1 }
317
+ })
318
+ .limit(batchSize)
319
+ .toArray();
320
+ throwIfClearAborted(signal);
321
+
322
+ if (documents.length === 0) {
323
+ return 0;
324
+ }
325
+ await collection.deleteMany(
326
+ {
327
+ _id: {
328
+ $in: documents.map((document) => document._id)
329
+ }
330
+ } as mongo.Filter<T>,
331
+ { maxTimeMS: lib_mongo.db.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
332
+ );
333
+ return documents.length;
334
+ },
335
+ signal,
336
+ throttleRate
337
+ );
338
+ }
339
+
161
340
  export const createPaginatedConnectionQuery = async <T extends mongo.Document>(
162
341
  query: mongo.Filter<T>,
163
342
  collection: mongo.Collection<T>,
@@ -1,80 +1,5 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`Mongo Sync Bucket Storage - Data > (insert, delete, insert), (delete) 1`] = `
4
- [
5
- {
6
- "checksum": 2871785649,
7
- "object_id": "test1",
8
- "op": "PUT",
9
- },
10
- {
11
- "checksum": 2872534815,
12
- "object_id": "test1",
13
- "op": "REMOVE",
14
- },
15
- {
16
- "checksum": 2871785649,
17
- "object_id": "test1",
18
- "op": "PUT",
19
- },
20
- {
21
- "checksum": 2872534815,
22
- "object_id": "test1",
23
- "op": "REMOVE",
24
- },
25
- ]
26
- `;
27
-
28
- exports[`Mongo Sync Bucket Storage - Data > (insert, delete, insert), (delete) 2`] = `
29
- [
30
- {
31
- "checksum": 2871785649,
32
- "object_id": "test1",
33
- "op": "PUT",
34
- },
35
- {
36
- "checksum": 2872534815,
37
- "object_id": "test1",
38
- "op": "REMOVE",
39
- },
40
- {
41
- "checksum": 2871785649,
42
- "object_id": "test1",
43
- "op": "PUT",
44
- },
45
- {
46
- "checksum": 2872534815,
47
- "object_id": "test1",
48
- "op": "REMOVE",
49
- },
50
- ]
51
- `;
52
-
53
- exports[`Mongo Sync Bucket Storage - Data > (insert, delete, insert), (delete) 3`] = `
54
- [
55
- {
56
- "checksum": 2871785649,
57
- "object_id": "test1",
58
- "op": "PUT",
59
- },
60
- {
61
- "checksum": 2872534815,
62
- "object_id": "test1",
63
- "op": "REMOVE",
64
- },
65
- {
66
- "checksum": 2871785649,
67
- "object_id": "test1",
68
- "op": "PUT",
69
- },
70
- {
71
- "checksum": 2872534815,
72
- "object_id": "test1",
73
- "op": "REMOVE",
74
- },
75
- ]
76
- `;
77
-
78
3
  exports[`Mongo Sync Bucket Storage - Data - v1 > (insert, delete, insert), (delete) 1`] = `
79
4
  [
80
5
  {