socket-function 1.1.23 → 1.1.25

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/index.d.ts CHANGED
@@ -609,13 +609,24 @@ declare module "socket-function/src/batching" {
609
609
  minDelay?: number;
610
610
  maxDelay?: number;
611
611
  }): T;
612
- export declare const safeLoop: typeof unblockLoop;
612
+ /** @deprecated Use safeLoop instead */
613
613
  export declare const throttledLoop: typeof unblockLoop;
614
+ /** @deprecated Use safeLoop instead */
614
615
  export declare function unblockLoop<T, R>(config: {
615
616
  data: T[];
616
617
  maxBlockingTime?: number;
617
618
  backOffTime?: number;
618
619
  } | T[], fnc: (item: T) => MaybePromise<R>): Promise<R[]>;
620
+ export declare function safeLoop<T, R>(config: {
621
+ data: T[];
622
+ fnc: (item: T) => MaybePromise<R>;
623
+ /** If set, yields after blocking for this many ms. ONLY applies if your function does not return promises. Default = 1000ms */
624
+ maxBlockingTime?: number;
625
+ /** Fraction of time spent active vs yielded. e.g. 0.5 => after running X ms, wait X ms before continuing. */
626
+ maxActiveFraction?: number;
627
+ doNotWarnOnSlow?: boolean;
628
+ name?: string;
629
+ }): Promise<R[]>;
619
630
 
620
631
  }
621
632
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "socket-function",
3
- "version": "1.1.23",
3
+ "version": "1.1.25",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "dependencies": {
package/src/batching.d.ts CHANGED
@@ -33,10 +33,21 @@ export declare function retryFunctional<T extends AnyFunction>(fnc: T, config?:
33
33
  minDelay?: number;
34
34
  maxDelay?: number;
35
35
  }): T;
36
- export declare const safeLoop: typeof unblockLoop;
36
+ /** @deprecated Use safeLoop instead */
37
37
  export declare const throttledLoop: typeof unblockLoop;
38
+ /** @deprecated Use safeLoop instead */
38
39
  export declare function unblockLoop<T, R>(config: {
39
40
  data: T[];
40
41
  maxBlockingTime?: number;
41
42
  backOffTime?: number;
42
43
  } | T[], fnc: (item: T) => MaybePromise<R>): Promise<R[]>;
44
+ export declare function safeLoop<T, R>(config: {
45
+ data: T[];
46
+ fnc: (item: T) => MaybePromise<R>;
47
+ /** If set, yields after blocking for this many ms. ONLY applies if your function does not return promises. Default = 1000ms */
48
+ maxBlockingTime?: number;
49
+ /** Fraction of time spent active vs yielded. e.g. 0.5 => after running X ms, wait X ms before continuing. */
50
+ maxActiveFraction?: number;
51
+ doNotWarnOnSlow?: boolean;
52
+ name?: string;
53
+ }): Promise<R[]>;
package/src/batching.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { formatTime } from "./formatting/format";
1
2
  import { PromiseObj, isNode, timeoutToError } from "./misc";
2
3
  import { measureWrap } from "./profiling/measure";
3
4
  import { AnyFunction, Args, MaybePromise } from "./types";
@@ -333,8 +334,9 @@ export function retryFunctional<T extends AnyFunction>(fnc: T, config?: {
333
334
  } as any;
334
335
  }
335
336
 
336
- export const safeLoop = unblockLoop;
337
+ /** @deprecated Use safeLoop instead */
337
338
  export const throttledLoop = unblockLoop;
339
+ /** @deprecated Use safeLoop instead */
338
340
  export async function unblockLoop<T, R>(config: {
339
341
  data: T[];
340
342
  maxBlockingTime?: number;
@@ -368,4 +370,75 @@ export async function unblockLoop<T, R>(config: {
368
370
  }
369
371
  }
370
372
  return results;
373
+ }
374
+
375
+ export async function safeLoop<T, R>(config: {
376
+ data: T[];
377
+ fnc: (item: T) => MaybePromise<R>;
378
+ /** If set, yields after blocking for this many ms. ONLY applies if your function does not return promises. Default = 1000ms */
379
+ maxBlockingTime?: number;
380
+ /** Fraction of time spent active vs yielded. e.g. 0.5 => after running X ms, wait X ms before continuing. */
381
+ maxActiveFraction?: number;
382
+ doNotWarnOnSlow?: boolean;
383
+ name?: string;
384
+ }): Promise<R[]> {
385
+ let { data, fnc, maxActiveFraction, doNotWarnOnSlow, name } = config;
386
+ let maxBlockingTime = config.maxBlockingTime ?? 1000;
387
+
388
+ let label = name || fnc.name || fnc.toString().slice(0, 100);
389
+ let startTime = Date.now();
390
+ let index = 0;
391
+ let indexStartTime = Date.now();
392
+ let done = false;
393
+
394
+ if (!doNotWarnOnSlow) {
395
+ void (async () => {
396
+ while (!done) {
397
+ await delay(5000);
398
+ if (done) break;
399
+ let message = `${label} @ ${index} / ${data.length} | ${formatTime(Date.now() - startTime)}`;
400
+ let timeOnCurrent = Date.now() - indexStartTime;
401
+ if (timeOnCurrent > 5000) {
402
+ message += `| SLOW INDEX (${index}) ${formatTime(timeOnCurrent)}+`;
403
+ }
404
+ console.log(message);
405
+ }
406
+ })();
407
+ }
408
+
409
+ let results: R[] = [];
410
+ let activeTimeSinceYield = 0;
411
+ try {
412
+ for (index = 0; index < data.length; index++) {
413
+ indexStartTime = Date.now();
414
+ let result = fnc(data[index]);
415
+ let isPromise = false;
416
+ if (result && typeof result === "object" && "then" in result) {
417
+ isPromise = true;
418
+ result = await result;
419
+ }
420
+ results.push(result);
421
+
422
+ activeTimeSinceYield += Date.now() - indexStartTime;
423
+
424
+ let backOffTime: number | undefined;
425
+
426
+ if (!isPromise && activeTimeSinceYield > maxBlockingTime) {
427
+ backOffTime = 0;
428
+ }
429
+
430
+ if (maxActiveFraction !== undefined && maxActiveFraction > 0 && maxActiveFraction < 1) {
431
+ let target = activeTimeSinceYield / maxActiveFraction - activeTimeSinceYield;
432
+ backOffTime = Math.max(backOffTime ?? 0, target);
433
+ }
434
+
435
+ if (backOffTime !== undefined) {
436
+ await delay(backOffTime);
437
+ activeTimeSinceYield = 0;
438
+ }
439
+ }
440
+ } finally {
441
+ done = true;
442
+ }
443
+ return results;
371
444
  }