@utaba/deep-memory-storage-cosmosdb 0.12.0 → 0.14.0
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.cjs +55 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +55 -33
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1127,41 +1127,71 @@ function isInTimeRange(timestamp, timeRange) {
|
|
|
1127
1127
|
|
|
1128
1128
|
// src/queries/adaptive-import.ts
|
|
1129
1129
|
var import_deep_memory5 = require("@utaba/deep-memory");
|
|
1130
|
-
var DEFAULT_MIN =
|
|
1130
|
+
var DEFAULT_MIN = 1;
|
|
1131
1131
|
var DEFAULT_START = 5;
|
|
1132
1132
|
var DEFAULT_MAX = 32;
|
|
1133
1133
|
var DEFAULT_INCREASE_AFTER = 50;
|
|
1134
1134
|
var DEFAULT_COOLDOWN_MS = 1e3;
|
|
1135
|
+
var DEFAULT_RAMP_UP_COOLDOWN_MS = 5e3;
|
|
1135
1136
|
var DEFAULT_MAX_CONSECUTIVE_THROTTLES_AT_MIN = 10;
|
|
1137
|
+
var DEFAULT_THROTTLE_CEILING_MULTIPLIER = 3;
|
|
1138
|
+
var NO_SOFT_CEILING = Number.POSITIVE_INFINITY;
|
|
1136
1139
|
function resolveOptions(opts) {
|
|
1137
1140
|
const min = Math.max(1, opts?.min ?? DEFAULT_MIN);
|
|
1138
1141
|
const max = Math.max(min, opts?.max ?? DEFAULT_MAX);
|
|
1139
1142
|
const start = Math.min(max, Math.max(min, opts?.start ?? DEFAULT_START));
|
|
1140
1143
|
const increaseAfter = Math.max(1, opts?.increaseAfter ?? DEFAULT_INCREASE_AFTER);
|
|
1141
1144
|
const cooldownMs = Math.max(0, opts?.cooldownMs ?? DEFAULT_COOLDOWN_MS);
|
|
1145
|
+
const rampUpCooldownMs = Math.max(0, opts?.rampUpCooldownMs ?? DEFAULT_RAMP_UP_COOLDOWN_MS);
|
|
1142
1146
|
const maxConsecutiveThrottlesAtMin = Math.max(
|
|
1143
1147
|
1,
|
|
1144
1148
|
opts?.maxConsecutiveThrottlesAtMin ?? DEFAULT_MAX_CONSECUTIVE_THROTTLES_AT_MIN
|
|
1145
1149
|
);
|
|
1150
|
+
const throttleCeilingMultiplier = Math.max(
|
|
1151
|
+
1,
|
|
1152
|
+
opts?.throttleCeilingMultiplier ?? DEFAULT_THROTTLE_CEILING_MULTIPLIER
|
|
1153
|
+
);
|
|
1146
1154
|
return {
|
|
1147
1155
|
min,
|
|
1148
1156
|
start,
|
|
1149
1157
|
max,
|
|
1150
1158
|
increaseAfter,
|
|
1151
1159
|
cooldownMs,
|
|
1160
|
+
rampUpCooldownMs,
|
|
1152
1161
|
maxConsecutiveThrottlesAtMin,
|
|
1162
|
+
throttleCeilingMultiplier,
|
|
1153
1163
|
onAdjust: opts?.onAdjust
|
|
1154
1164
|
};
|
|
1155
1165
|
}
|
|
1166
|
+
function resolveController(options, handle) {
|
|
1167
|
+
if (!handle) {
|
|
1168
|
+
return new AdaptiveConcurrencyController(options);
|
|
1169
|
+
}
|
|
1170
|
+
const cosmosHandle = handle;
|
|
1171
|
+
if (!cosmosHandle.controller) {
|
|
1172
|
+
cosmosHandle.controller = new AdaptiveConcurrencyController(options);
|
|
1173
|
+
}
|
|
1174
|
+
return cosmosHandle.controller;
|
|
1175
|
+
}
|
|
1156
1176
|
var AdaptiveConcurrencyController = class {
|
|
1157
1177
|
opts;
|
|
1158
1178
|
current;
|
|
1159
1179
|
streak = 0;
|
|
1160
1180
|
cooldownUntil = 0;
|
|
1181
|
+
rampFrozenUntil = 0;
|
|
1161
1182
|
completed = 0;
|
|
1162
1183
|
throttled = 0;
|
|
1163
1184
|
startEmitted = false;
|
|
1164
1185
|
consecutiveThrottlesAtMin = 0;
|
|
1186
|
+
/**
|
|
1187
|
+
* Highest concurrency at which a throttle has been observed and the
|
|
1188
|
+
* controller actually halved (i.e. concrete evidence the cluster could not
|
|
1189
|
+
* sustain that level). Re-approaching this level on subsequent ramp-ups
|
|
1190
|
+
* requires `increaseAfter * throttleCeilingMultiplier` consecutive successes
|
|
1191
|
+
* instead of just `increaseAfter`. Cleared once we've successfully held the
|
|
1192
|
+
* level without further throttling — see noteSuccess.
|
|
1193
|
+
*/
|
|
1194
|
+
softCeiling = NO_SOFT_CEILING;
|
|
1165
1195
|
constructor(opts) {
|
|
1166
1196
|
this.opts = resolveOptions(opts);
|
|
1167
1197
|
this.current = this.opts.start;
|
|
@@ -1199,14 +1229,21 @@ var AdaptiveConcurrencyController = class {
|
|
|
1199
1229
|
this.notify("start", this.current);
|
|
1200
1230
|
}
|
|
1201
1231
|
/** Record a throttle-free task completion. May trigger ramp-up. */
|
|
1202
|
-
noteSuccess() {
|
|
1232
|
+
noteSuccess(now = Date.now()) {
|
|
1203
1233
|
this.completed++;
|
|
1204
|
-
this.streak++;
|
|
1205
1234
|
this.consecutiveThrottlesAtMin = 0;
|
|
1206
|
-
if (
|
|
1235
|
+
if (now < this.rampFrozenUntil) return;
|
|
1236
|
+
this.streak++;
|
|
1237
|
+
if (this.current >= this.opts.max) return;
|
|
1238
|
+
const target = this.current + 1;
|
|
1239
|
+
const needed = target >= this.softCeiling ? this.opts.increaseAfter * this.opts.throttleCeilingMultiplier : this.opts.increaseAfter;
|
|
1240
|
+
if (this.streak >= needed) {
|
|
1207
1241
|
const previous = this.current;
|
|
1208
|
-
this.current = Math.min(this.opts.max,
|
|
1242
|
+
this.current = Math.min(this.opts.max, target);
|
|
1209
1243
|
this.streak = 0;
|
|
1244
|
+
if (this.current >= this.softCeiling) {
|
|
1245
|
+
this.softCeiling = NO_SOFT_CEILING;
|
|
1246
|
+
}
|
|
1210
1247
|
this.notify("ramp-up", previous);
|
|
1211
1248
|
}
|
|
1212
1249
|
}
|
|
@@ -1218,8 +1255,10 @@ var AdaptiveConcurrencyController = class {
|
|
|
1218
1255
|
const previous = this.current;
|
|
1219
1256
|
const next = Math.max(this.opts.min, Math.floor(this.current / 2));
|
|
1220
1257
|
this.cooldownUntil = now + this.opts.cooldownMs;
|
|
1258
|
+
this.rampFrozenUntil = now + this.opts.rampUpCooldownMs;
|
|
1221
1259
|
if (next !== previous) {
|
|
1222
1260
|
this.current = next;
|
|
1261
|
+
this.softCeiling = previous;
|
|
1223
1262
|
this.notify("throttle", previous);
|
|
1224
1263
|
}
|
|
1225
1264
|
if (this.current === this.opts.min) {
|
|
@@ -1228,6 +1267,15 @@ var AdaptiveConcurrencyController = class {
|
|
|
1228
1267
|
this.consecutiveThrottlesAtMin = 0;
|
|
1229
1268
|
}
|
|
1230
1269
|
}
|
|
1270
|
+
/**
|
|
1271
|
+
* Current soft ceiling — the highest concurrency at which a throttle was
|
|
1272
|
+
* observed and the controller halved. {@link Number.POSITIVE_INFINITY} when
|
|
1273
|
+
* no ceiling is in effect. Re-approaching this level requires
|
|
1274
|
+
* `increaseAfter * throttleCeilingMultiplier` consecutive successes.
|
|
1275
|
+
*/
|
|
1276
|
+
getSoftCeiling() {
|
|
1277
|
+
return this.softCeiling;
|
|
1278
|
+
}
|
|
1231
1279
|
/** Configured circuit-breaker threshold. */
|
|
1232
1280
|
getMaxConsecutiveThrottlesAtMin() {
|
|
1233
1281
|
return this.opts.maxConsecutiveThrottlesAtMin;
|
|
@@ -1408,7 +1456,7 @@ async function importBulk(conn, repositoryId, data, options) {
|
|
|
1408
1456
|
let relationshipsImported = 0;
|
|
1409
1457
|
const errors = [];
|
|
1410
1458
|
const skipCheck = options?.skipExistenceCheck ?? false;
|
|
1411
|
-
const controller =
|
|
1459
|
+
const controller = resolveController(options?.adaptiveConcurrency, options?.adaptiveConcurrencyHandle);
|
|
1412
1460
|
for (const chunk of data) {
|
|
1413
1461
|
if (chunk.entities && chunk.entities.length > 0) {
|
|
1414
1462
|
const results = await runAdaptive(
|
|
@@ -2173,35 +2221,9 @@ var CosmosDbProvider = class {
|
|
|
2173
2221
|
return this.track("executeNativeQuery", void 0, () => this.executeNativeQueryImpl(query, params));
|
|
2174
2222
|
}
|
|
2175
2223
|
async executeNativeQueryImpl(query, params) {
|
|
2176
|
-
const startTime = Date.now();
|
|
2177
2224
|
try {
|
|
2178
2225
|
const result = await this.conn.submit(query, params);
|
|
2179
|
-
|
|
2180
|
-
const entities = [];
|
|
2181
|
-
for (const item of result.items) {
|
|
2182
|
-
try {
|
|
2183
|
-
const entity = entityFromGremlin(item);
|
|
2184
|
-
if (entity.id) {
|
|
2185
|
-
entities.push(entity);
|
|
2186
|
-
}
|
|
2187
|
-
} catch {
|
|
2188
|
-
}
|
|
2189
|
-
}
|
|
2190
|
-
const queryMetadata = {
|
|
2191
|
-
executionTimeMs,
|
|
2192
|
-
resourceCost: result.requestCharge != null ? { units: "RU", value: result.requestCharge } : void 0,
|
|
2193
|
-
compiledQuery: query,
|
|
2194
|
-
compiledQueryLanguage: "gremlin",
|
|
2195
|
-
appliedLimits: { maxResults: entities.length },
|
|
2196
|
-
truncated: false
|
|
2197
|
-
};
|
|
2198
|
-
return {
|
|
2199
|
-
entities,
|
|
2200
|
-
total: entities.length,
|
|
2201
|
-
returned: entities.length,
|
|
2202
|
-
hasMore: false,
|
|
2203
|
-
queryMetadata
|
|
2204
|
-
};
|
|
2226
|
+
return result.items;
|
|
2205
2227
|
} catch (err) {
|
|
2206
2228
|
throw new import_deep_memory6.ProviderError(
|
|
2207
2229
|
`Native Gremlin query failed: ${err instanceof Error ? err.message : String(err)}`,
|