@utaba/deep-memory-storage-cosmosdb 0.12.0 → 0.12.1

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.
package/dist/index.js CHANGED
@@ -1090,12 +1090,14 @@ function isInTimeRange(timestamp, timeRange) {
1090
1090
 
1091
1091
  // src/queries/adaptive-import.ts
1092
1092
  import { ImportThrottleAbortError } from "@utaba/deep-memory";
1093
- var DEFAULT_MIN = 2;
1093
+ var DEFAULT_MIN = 1;
1094
1094
  var DEFAULT_START = 5;
1095
1095
  var DEFAULT_MAX = 32;
1096
1096
  var DEFAULT_INCREASE_AFTER = 50;
1097
1097
  var DEFAULT_COOLDOWN_MS = 1e3;
1098
1098
  var DEFAULT_MAX_CONSECUTIVE_THROTTLES_AT_MIN = 10;
1099
+ var DEFAULT_THROTTLE_CEILING_MULTIPLIER = 3;
1100
+ var NO_SOFT_CEILING = Number.POSITIVE_INFINITY;
1099
1101
  function resolveOptions(opts) {
1100
1102
  const min = Math.max(1, opts?.min ?? DEFAULT_MIN);
1101
1103
  const max = Math.max(min, opts?.max ?? DEFAULT_MAX);
@@ -1106,6 +1108,10 @@ function resolveOptions(opts) {
1106
1108
  1,
1107
1109
  opts?.maxConsecutiveThrottlesAtMin ?? DEFAULT_MAX_CONSECUTIVE_THROTTLES_AT_MIN
1108
1110
  );
1111
+ const throttleCeilingMultiplier = Math.max(
1112
+ 1,
1113
+ opts?.throttleCeilingMultiplier ?? DEFAULT_THROTTLE_CEILING_MULTIPLIER
1114
+ );
1109
1115
  return {
1110
1116
  min,
1111
1117
  start,
@@ -1113,9 +1119,20 @@ function resolveOptions(opts) {
1113
1119
  increaseAfter,
1114
1120
  cooldownMs,
1115
1121
  maxConsecutiveThrottlesAtMin,
1122
+ throttleCeilingMultiplier,
1116
1123
  onAdjust: opts?.onAdjust
1117
1124
  };
1118
1125
  }
1126
+ function resolveController(options, handle) {
1127
+ if (!handle) {
1128
+ return new AdaptiveConcurrencyController(options);
1129
+ }
1130
+ const cosmosHandle = handle;
1131
+ if (!cosmosHandle.controller) {
1132
+ cosmosHandle.controller = new AdaptiveConcurrencyController(options);
1133
+ }
1134
+ return cosmosHandle.controller;
1135
+ }
1119
1136
  var AdaptiveConcurrencyController = class {
1120
1137
  opts;
1121
1138
  current;
@@ -1125,6 +1142,15 @@ var AdaptiveConcurrencyController = class {
1125
1142
  throttled = 0;
1126
1143
  startEmitted = false;
1127
1144
  consecutiveThrottlesAtMin = 0;
1145
+ /**
1146
+ * Highest concurrency at which a throttle has been observed and the
1147
+ * controller actually halved (i.e. concrete evidence the cluster could not
1148
+ * sustain that level). Re-approaching this level on subsequent ramp-ups
1149
+ * requires `increaseAfter * throttleCeilingMultiplier` consecutive successes
1150
+ * instead of just `increaseAfter`. Cleared once we've successfully held the
1151
+ * level without further throttling — see noteSuccess.
1152
+ */
1153
+ softCeiling = NO_SOFT_CEILING;
1128
1154
  constructor(opts) {
1129
1155
  this.opts = resolveOptions(opts);
1130
1156
  this.current = this.opts.start;
@@ -1166,10 +1192,16 @@ var AdaptiveConcurrencyController = class {
1166
1192
  this.completed++;
1167
1193
  this.streak++;
1168
1194
  this.consecutiveThrottlesAtMin = 0;
1169
- if (this.streak >= this.opts.increaseAfter && this.current < this.opts.max) {
1195
+ if (this.current >= this.opts.max) return;
1196
+ const target = this.current + 1;
1197
+ const needed = target >= this.softCeiling ? this.opts.increaseAfter * this.opts.throttleCeilingMultiplier : this.opts.increaseAfter;
1198
+ if (this.streak >= needed) {
1170
1199
  const previous = this.current;
1171
- this.current = Math.min(this.opts.max, this.current + 1);
1200
+ this.current = Math.min(this.opts.max, target);
1172
1201
  this.streak = 0;
1202
+ if (this.current >= this.softCeiling) {
1203
+ this.softCeiling = NO_SOFT_CEILING;
1204
+ }
1173
1205
  this.notify("ramp-up", previous);
1174
1206
  }
1175
1207
  }
@@ -1183,6 +1215,7 @@ var AdaptiveConcurrencyController = class {
1183
1215
  this.cooldownUntil = now + this.opts.cooldownMs;
1184
1216
  if (next !== previous) {
1185
1217
  this.current = next;
1218
+ this.softCeiling = previous;
1186
1219
  this.notify("throttle", previous);
1187
1220
  }
1188
1221
  if (this.current === this.opts.min) {
@@ -1191,6 +1224,15 @@ var AdaptiveConcurrencyController = class {
1191
1224
  this.consecutiveThrottlesAtMin = 0;
1192
1225
  }
1193
1226
  }
1227
+ /**
1228
+ * Current soft ceiling — the highest concurrency at which a throttle was
1229
+ * observed and the controller halved. {@link Number.POSITIVE_INFINITY} when
1230
+ * no ceiling is in effect. Re-approaching this level requires
1231
+ * `increaseAfter * throttleCeilingMultiplier` consecutive successes.
1232
+ */
1233
+ getSoftCeiling() {
1234
+ return this.softCeiling;
1235
+ }
1194
1236
  /** Configured circuit-breaker threshold. */
1195
1237
  getMaxConsecutiveThrottlesAtMin() {
1196
1238
  return this.opts.maxConsecutiveThrottlesAtMin;
@@ -1371,7 +1413,7 @@ async function importBulk(conn, repositoryId, data, options) {
1371
1413
  let relationshipsImported = 0;
1372
1414
  const errors = [];
1373
1415
  const skipCheck = options?.skipExistenceCheck ?? false;
1374
- const controller = new AdaptiveConcurrencyController(options?.adaptiveConcurrency);
1416
+ const controller = resolveController(options?.adaptiveConcurrency, options?.adaptiveConcurrencyHandle);
1375
1417
  for (const chunk of data) {
1376
1418
  if (chunk.entities && chunk.entities.length > 0) {
1377
1419
  const results = await runAdaptive(