@lde/distribution-probe 0.2.8 → 0.2.10
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/probe.d.ts.map +1 -1
- package/dist/probe.js +5 -67
- package/package.json +3 -2
package/dist/probe.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../src/probe.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../src/probe.ts"],"names":[],"mappings":"AAKA,OAAO,EAAyB,YAAY,EAAE,MAAM,cAAc,CAAC;AAKnE;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;OAUG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;;;;OASG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACpD;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzD;AAkCD;;GAEG;AACH,qBAAa,YAAY;aAEL,GAAG,EAAE,MAAM;aACX,OAAO,EAAE,MAAM;aACf,cAAc,EAAE,MAAM;gBAFtB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,MAAM;CAEzC;AAED;;GAEG;AACH,uBAAe,WAAW;aAUN,GAAG,EAAE,MAAM;IAT7B,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,YAAY,EAAE,IAAI,GAAG,IAAI,CAAQ;IACjD,SAAgB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,SAAgB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,SAAgB,QAAQ,EAAE,MAAM,EAAE,CAAM;IACxC,SAAgB,cAAc,EAAE,MAAM,CAAC;gBAGrB,GAAG,EAAE,MAAM,EAC3B,QAAQ,EAAE,QAAQ,EAClB,cAAc,EAAE,MAAM,EACtB,aAAa,GAAE,MAAM,GAAG,IAAW;IAa9B,SAAS,IAAI,OAAO;CAO5B;AAqBD;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,WAAW;IAChD;;;;;OAKG;IACH,SAAgB,oBAAoB,EAAE,SAAS,MAAM,EAAE,CAAC;gBAGtD,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,cAAc,EAAE,MAAM,EACtB,oBAAoB,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EAChD,aAAa,GAAE,MAAM,GAAG,IAAW;IAS5B,SAAS,IAAI,OAAO;CAQ9B;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,WAAW;IAClD,SAAgB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;gBAGhD,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,cAAc,EAAE,MAAM,EACtB,aAAa,GAAE,MAAM,GAAG,IAAW;CAQtC;AAED,MAAM,MAAM,eAAe,GACzB,iBAAiB,GAAG,mBAAmB,GAAG,YAAY,CAAC;AAIzD;;;;;;;;;GASG;AACH,wBAAsB,KAAK,CACzB,YAAY,EAAE,YAAY,EAC1B,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,eAAe,CAAC,CAqD1B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,SAAS,CAC7B,aAAa,EAAE,SAAS,YAAY,EAAE,EACtC,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,eAAe,EAAE,CAAC,CAsC5B"}
|
package/dist/probe.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { hostKeyOf, mapHostLimited, positiveIntOrDefault, } from '@lde/host-limiter';
|
|
1
2
|
import { compressionMediaTypes } from '@lde/dataset';
|
|
2
3
|
import { rdfParser } from 'rdf-parse';
|
|
3
4
|
import { Readable } from 'node:stream';
|
|
@@ -192,10 +193,10 @@ export async function probeMany(distributions, options) {
|
|
|
192
193
|
// the caller.
|
|
193
194
|
const globalLimit = positiveIntOrDefault(options?.concurrency, DEFAULT_PROBE_CONCURRENCY);
|
|
194
195
|
const perHostLimit = positiveIntOrDefault(options?.perHostConcurrency, DEFAULT_PROBE_PER_HOST_CONCURRENCY);
|
|
195
|
-
// Probes contend per host
|
|
196
|
-
// empty host, so it falls back to its full href and never
|
|
197
|
-
// an unrelated one.
|
|
198
|
-
const hostKeys = distributions.map((distribution) => distribution.accessUrl
|
|
196
|
+
// Probes contend per host, by the shared rule: an authority-less URL (e.g.
|
|
197
|
+
// urn:, file:) has an empty host, so it falls back to its full href and never
|
|
198
|
+
// shares a budget with an unrelated one.
|
|
199
|
+
const hostKeys = distributions.map((distribution) => hostKeyOf(distribution.accessUrl));
|
|
199
200
|
// Report progress as each probe settles. mapHostLimited resolves results in
|
|
200
201
|
// input order, but tasks complete out of order, so count completions here
|
|
201
202
|
// rather than rely on result position. The total is the batch size.
|
|
@@ -209,69 +210,6 @@ export async function probeMany(distributions, options) {
|
|
|
209
210
|
return result;
|
|
210
211
|
});
|
|
211
212
|
}
|
|
212
|
-
/**
|
|
213
|
-
* Coerce an optional concurrency budget to a usable value: a positive integer is
|
|
214
|
-
* taken as-is; undefined, zero, negative, fractional, or NaN falls back to the
|
|
215
|
-
* default. Matches probe()’s treatment of an invalid retries value.
|
|
216
|
-
*/
|
|
217
|
-
function positiveIntOrDefault(value, fallback) {
|
|
218
|
-
return value !== undefined && Number.isInteger(value) && value >= 1
|
|
219
|
-
? value
|
|
220
|
-
: fallback;
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* Run `task` over `items` with two concurrency caps — a global cap and a per-host
|
|
224
|
-
* cap keyed by `hostKeys[index]` — resolving to results in input order. When the
|
|
225
|
-
* next queued item’s host is at the per-host cap it is skipped for a later item on
|
|
226
|
-
* a different host, so a saturated host never idles the global pool (no head-of-line
|
|
227
|
-
* blocking); the skipped host always has a task in flight, whose completion re-runs
|
|
228
|
-
* the scheduler, so the queue always drains. `task` must not reject — callers wrap
|
|
229
|
-
* failures into a result value — as a rejection would leave the promise pending.
|
|
230
|
-
*/
|
|
231
|
-
function mapHostLimited(items, hostKeys, globalLimit, perHostLimit, task) {
|
|
232
|
-
const results = new Array(items.length);
|
|
233
|
-
const perHostInFlight = new Map();
|
|
234
|
-
const pending = items.map((_unused, index) => index);
|
|
235
|
-
let globalInFlight = 0;
|
|
236
|
-
let settledCount = 0;
|
|
237
|
-
const adjustHost = (host, delta) => {
|
|
238
|
-
perHostInFlight.set(host, (perHostInFlight.get(host) ?? 0) + delta);
|
|
239
|
-
};
|
|
240
|
-
return new Promise((resolve) => {
|
|
241
|
-
const schedule = () => {
|
|
242
|
-
let cursor = 0;
|
|
243
|
-
while (cursor < pending.length && globalInFlight < globalLimit) {
|
|
244
|
-
const index = pending[cursor];
|
|
245
|
-
const host = hostKeys[index];
|
|
246
|
-
if ((perHostInFlight.get(host) ?? 0) >= perHostLimit) {
|
|
247
|
-
cursor++; // Host saturated; leave it queued and try a later, different host.
|
|
248
|
-
continue;
|
|
249
|
-
}
|
|
250
|
-
pending.splice(cursor, 1);
|
|
251
|
-
globalInFlight++;
|
|
252
|
-
adjustHost(host, 1);
|
|
253
|
-
void task(items[index]).then((result) => {
|
|
254
|
-
results[index] = result;
|
|
255
|
-
globalInFlight--;
|
|
256
|
-
adjustHost(host, -1);
|
|
257
|
-
settledCount++;
|
|
258
|
-
if (settledCount === items.length) {
|
|
259
|
-
resolve(results);
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
schedule();
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
// pending[cursor] now holds the next queued item; do not advance cursor.
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
schedule();
|
|
269
|
-
// Resolve immediately when there is nothing to settle (empty input); a
|
|
270
|
-
// non-empty run resolves via the task completion above.
|
|
271
|
-
if (settledCount === items.length)
|
|
272
|
-
resolve(results);
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
213
|
function delay(milliseconds) {
|
|
276
214
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
277
215
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lde/distribution-probe",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
4
4
|
"repository": {
|
|
5
5
|
"url": "git+https://github.com/ldelements/lde.git",
|
|
6
6
|
"directory": "packages/distribution-probe"
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
"!**/*.tsbuildinfo"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@lde/dataset": "^0.7.
|
|
27
|
+
"@lde/dataset": "^0.7.10",
|
|
28
|
+
"@lde/host-limiter": "^0.0.2",
|
|
28
29
|
"rdf-parse": "^5.0.0",
|
|
29
30
|
"tslib": "^2.3.0"
|
|
30
31
|
}
|