socket-function 1.1.22 → 1.1.24

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,25 @@ 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. */
624
+ maxBlockingTime?: number;
625
+ /** If set (with maxBlockingTime), the fraction of time spent active vs yielded.
626
+ * e.g. 0.5 => after blocking X ms, wait X ms before continuing. */
627
+ maxActiveFraction?: number;
628
+ doNotWarnOnSlow?: boolean;
629
+ name?: string;
630
+ }): Promise<R[]>;
619
631
 
620
632
  }
621
633
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "socket-function",
3
- "version": "1.1.22",
3
+ "version": "1.1.24",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "dependencies": {
package/src/batching.d.ts CHANGED
@@ -33,10 +33,22 @@ 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. */
48
+ maxBlockingTime?: number;
49
+ /** If set (with maxBlockingTime), the fraction of time spent active vs yielded.
50
+ * e.g. 0.5 => after blocking X ms, wait X ms before continuing. */
51
+ maxActiveFraction?: number;
52
+ doNotWarnOnSlow?: boolean;
53
+ name?: string;
54
+ }): 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,67 @@ 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. */
379
+ maxBlockingTime?: number;
380
+ /** If set (with maxBlockingTime), the fraction of time spent active vs yielded.
381
+ * e.g. 0.5 => after blocking X ms, wait X ms before continuing. */
382
+ maxActiveFraction?: number;
383
+ doNotWarnOnSlow?: boolean;
384
+ name?: string;
385
+ }): Promise<R[]> {
386
+ let { data, fnc, maxBlockingTime, maxActiveFraction, doNotWarnOnSlow, name } = config;
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 lastYieldTime = Date.now();
411
+ try {
412
+ for (index = 0; index < data.length; index++) {
413
+ indexStartTime = Date.now();
414
+ let result = fnc(data[index]);
415
+ if (result && typeof result === "object" && "then" in result) {
416
+ result = await result;
417
+ }
418
+ results.push(result);
419
+
420
+ if (maxBlockingTime !== undefined) {
421
+ let blockedFor = Date.now() - lastYieldTime;
422
+ if (blockedFor > maxBlockingTime) {
423
+ let backOffTime = 0;
424
+ if (maxActiveFraction !== undefined && maxActiveFraction > 0 && maxActiveFraction < 1) {
425
+ backOffTime = blockedFor / maxActiveFraction - blockedFor;
426
+ }
427
+ await delay(backOffTime);
428
+ lastYieldTime = Date.now();
429
+ }
430
+ }
431
+ }
432
+ } finally {
433
+ done = true;
434
+ }
435
+ return results;
371
436
  }
@@ -59,18 +59,18 @@ function connectPromiseToCallbackObj(promise: any, callbackObj: any) {
59
59
  // We need to delete the callback lists once on finally happens. Because we only connect to the promise once, And so it'll only trigger us once. So removing it is the only way to get it to trigger us again if someone subscribes to a finished promise.
60
60
  promiseCallbacks.delete(promise);
61
61
  for (let fnc of callbackObj.onResolve.slice()) {
62
- try { fnc(value); } finally { }
62
+ try { fnc(value); } catch { }
63
63
  }
64
64
  },
65
65
  (value: any) => {
66
66
  promiseCallbacks.delete(promise);
67
67
  for (let fnc of callbackObj.onReject.slice()) {
68
- try { fnc(value); } finally { }
68
+ try { fnc(value); } catch { }
69
69
  }
70
70
  }
71
71
  ).finally(() => {
72
72
  for (let fnc of callbackObj.onFinally.slice()) {
73
- try { fnc(); } finally { }
73
+ try { fnc(); } catch { }
74
74
  }
75
75
  });
76
76
  }