@effectionx/timebox 0.1.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/README.md +27 -0
- package/esm/mod.d.ts +69 -0
- package/esm/mod.d.ts.map +1 -0
- package/esm/mod.js +36 -0
- package/esm/package.json +3 -0
- package/package.json +29 -0
- package/script/mod.d.ts +69 -0
- package/script/mod.d.ts.map +1 -0
- package/script/mod.js +39 -0
- package/script/package.json +3 -0
package/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Timebox
|
|
2
|
+
|
|
3
|
+
Constrain any operation to complete within a certain time.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Very often you want to put a limit on how long an operation may run such as a
|
|
8
|
+
`fetch()` of an external resource, or handling a web request. To do this, you
|
|
9
|
+
can use the `timebox()` function. It will encapsulate the operation and either
|
|
10
|
+
return its result, or a otherwise a "timeout" object indicating that it did not
|
|
11
|
+
complete in the required time.
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { timebox } from "@effectionx/timebox";
|
|
15
|
+
import { handleRequest } from "./handle-request";
|
|
16
|
+
|
|
17
|
+
// a theoretical request handler
|
|
18
|
+
export function* handler(request) {
|
|
19
|
+
// do not let the handler run for more than 10 seconds
|
|
20
|
+
let result = yield* timebox(10000, () => handleRequest(request));
|
|
21
|
+
if (result.timeout) {
|
|
22
|
+
return new Response(504, "Gateway Timeout");
|
|
23
|
+
} else {
|
|
24
|
+
return result.value;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
package/esm/mod.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { Operation } from "effection";
|
|
2
|
+
/**
|
|
3
|
+
* Either a succesfully computed value, or one that took too long to complete.
|
|
4
|
+
*/
|
|
5
|
+
export type Timeboxed<T> = Completed<T> | Timeout;
|
|
6
|
+
/**
|
|
7
|
+
* A value successfully computed within the timeout window. It has metadata about how long it
|
|
8
|
+
* took.
|
|
9
|
+
*/
|
|
10
|
+
export interface Completed<T> {
|
|
11
|
+
/**
|
|
12
|
+
* false: indicates that there was no timeout and that value was successfully computed
|
|
13
|
+
*/
|
|
14
|
+
readonly timeout: false;
|
|
15
|
+
/**
|
|
16
|
+
* The actual value
|
|
17
|
+
*/
|
|
18
|
+
readonly value: T;
|
|
19
|
+
/**
|
|
20
|
+
* The time that the operation began;
|
|
21
|
+
*/
|
|
22
|
+
readonly start: DOMHighResTimeStamp;
|
|
23
|
+
/**
|
|
24
|
+
* The time that the operation succesfully returned value
|
|
25
|
+
*/
|
|
26
|
+
readonly end: DOMHighResTimeStamp;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A value that did not compute within the alloted window.
|
|
30
|
+
*/
|
|
31
|
+
export interface Timeout {
|
|
32
|
+
/**
|
|
33
|
+
* true: indicates that this is a timed out result and no value is available
|
|
34
|
+
*/
|
|
35
|
+
readonly timeout: true;
|
|
36
|
+
/**
|
|
37
|
+
* The time that the operation began;
|
|
38
|
+
*/
|
|
39
|
+
readonly start: DOMHighResTimeStamp;
|
|
40
|
+
/**
|
|
41
|
+
* The time that the operation succesfully returned value
|
|
42
|
+
*/
|
|
43
|
+
readonly end: DOMHighResTimeStamp;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Constrain `operation` to complete within `limitMS` milliseconds
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* import { timebox } from "@effectionx/timebox";
|
|
51
|
+
* import { handleRequest } from "./handle-request";
|
|
52
|
+
|
|
53
|
+
* // a theoretical request handler
|
|
54
|
+
* export function* handler(request: Request): Operation<Response> {
|
|
55
|
+
* // do not let the handler run for more than 10 seconds
|
|
56
|
+
* let result = yield* timebox(10000, () => handleRequest(request));
|
|
57
|
+
* if (result.timeout) {
|
|
58
|
+
* return new Response(504, "Gateway Timeout");
|
|
59
|
+
* } else {
|
|
60
|
+
* return result.value;
|
|
61
|
+
* }
|
|
62
|
+
* }
|
|
63
|
+
* ```
|
|
64
|
+
* @param limitMS - the maximum allowable time for `operation` to complete
|
|
65
|
+
* @param operation - the operation to attempt
|
|
66
|
+
* @returns either a completed value or a timeout
|
|
67
|
+
*/
|
|
68
|
+
export declare function timebox<T>(limitMS: number, operation: () => Operation<T>): Operation<Timeboxed<T>>;
|
|
69
|
+
//# sourceMappingURL=mod.d.ts.map
|
package/esm/mod.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;AAElD;;;GAGG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IAExB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAElB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,mBAAmB,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IAEvB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,mBAAmB,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,OAAO,CAAC,CAAC,EACvB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,SAAS,CAAC,CAAC,CAAC,GAC5B,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAEzB"}
|
package/esm/mod.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { race, sleep } from "effection";
|
|
2
|
+
/**
|
|
3
|
+
* Constrain `operation` to complete within `limitMS` milliseconds
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { timebox } from "@effectionx/timebox";
|
|
8
|
+
* import { handleRequest } from "./handle-request";
|
|
9
|
+
|
|
10
|
+
* // a theoretical request handler
|
|
11
|
+
* export function* handler(request: Request): Operation<Response> {
|
|
12
|
+
* // do not let the handler run for more than 10 seconds
|
|
13
|
+
* let result = yield* timebox(10000, () => handleRequest(request));
|
|
14
|
+
* if (result.timeout) {
|
|
15
|
+
* return new Response(504, "Gateway Timeout");
|
|
16
|
+
* } else {
|
|
17
|
+
* return result.value;
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
* @param limitMS - the maximum allowable time for `operation` to complete
|
|
22
|
+
* @param operation - the operation to attempt
|
|
23
|
+
* @returns either a completed value or a timeout
|
|
24
|
+
*/
|
|
25
|
+
export function timebox(limitMS, operation) {
|
|
26
|
+
return race([complete(operation), deadline(limitMS)]);
|
|
27
|
+
}
|
|
28
|
+
function* deadline(limitMS) {
|
|
29
|
+
let start = performance.now();
|
|
30
|
+
yield* sleep(limitMS);
|
|
31
|
+
return { timeout: true, start, end: performance.now() };
|
|
32
|
+
}
|
|
33
|
+
function* complete(op) {
|
|
34
|
+
let start = performance.now();
|
|
35
|
+
return { timeout: false, value: yield* op(), start, end: performance.now() };
|
|
36
|
+
}
|
package/esm/package.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@effectionx/timebox",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"author": "engineering@frontside.com",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/thefrontside/effectionx.git"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/thefrontside/effectionx/issues"
|
|
12
|
+
},
|
|
13
|
+
"main": "./script/mod.js",
|
|
14
|
+
"module": "./esm/mod.js",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": "./esm/mod.js",
|
|
18
|
+
"require": "./script/mod.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">= 16"
|
|
23
|
+
},
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"effection": "^4.0.0-alpha.4"
|
|
27
|
+
},
|
|
28
|
+
"_generatedBy": "dnt@dev"
|
|
29
|
+
}
|
package/script/mod.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { Operation } from "effection";
|
|
2
|
+
/**
|
|
3
|
+
* Either a succesfully computed value, or one that took too long to complete.
|
|
4
|
+
*/
|
|
5
|
+
export type Timeboxed<T> = Completed<T> | Timeout;
|
|
6
|
+
/**
|
|
7
|
+
* A value successfully computed within the timeout window. It has metadata about how long it
|
|
8
|
+
* took.
|
|
9
|
+
*/
|
|
10
|
+
export interface Completed<T> {
|
|
11
|
+
/**
|
|
12
|
+
* false: indicates that there was no timeout and that value was successfully computed
|
|
13
|
+
*/
|
|
14
|
+
readonly timeout: false;
|
|
15
|
+
/**
|
|
16
|
+
* The actual value
|
|
17
|
+
*/
|
|
18
|
+
readonly value: T;
|
|
19
|
+
/**
|
|
20
|
+
* The time that the operation began;
|
|
21
|
+
*/
|
|
22
|
+
readonly start: DOMHighResTimeStamp;
|
|
23
|
+
/**
|
|
24
|
+
* The time that the operation succesfully returned value
|
|
25
|
+
*/
|
|
26
|
+
readonly end: DOMHighResTimeStamp;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A value that did not compute within the alloted window.
|
|
30
|
+
*/
|
|
31
|
+
export interface Timeout {
|
|
32
|
+
/**
|
|
33
|
+
* true: indicates that this is a timed out result and no value is available
|
|
34
|
+
*/
|
|
35
|
+
readonly timeout: true;
|
|
36
|
+
/**
|
|
37
|
+
* The time that the operation began;
|
|
38
|
+
*/
|
|
39
|
+
readonly start: DOMHighResTimeStamp;
|
|
40
|
+
/**
|
|
41
|
+
* The time that the operation succesfully returned value
|
|
42
|
+
*/
|
|
43
|
+
readonly end: DOMHighResTimeStamp;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Constrain `operation` to complete within `limitMS` milliseconds
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* import { timebox } from "@effectionx/timebox";
|
|
51
|
+
* import { handleRequest } from "./handle-request";
|
|
52
|
+
|
|
53
|
+
* // a theoretical request handler
|
|
54
|
+
* export function* handler(request: Request): Operation<Response> {
|
|
55
|
+
* // do not let the handler run for more than 10 seconds
|
|
56
|
+
* let result = yield* timebox(10000, () => handleRequest(request));
|
|
57
|
+
* if (result.timeout) {
|
|
58
|
+
* return new Response(504, "Gateway Timeout");
|
|
59
|
+
* } else {
|
|
60
|
+
* return result.value;
|
|
61
|
+
* }
|
|
62
|
+
* }
|
|
63
|
+
* ```
|
|
64
|
+
* @param limitMS - the maximum allowable time for `operation` to complete
|
|
65
|
+
* @param operation - the operation to attempt
|
|
66
|
+
* @returns either a completed value or a timeout
|
|
67
|
+
*/
|
|
68
|
+
export declare function timebox<T>(limitMS: number, operation: () => Operation<T>): Operation<Timeboxed<T>>;
|
|
69
|
+
//# sourceMappingURL=mod.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;AAElD;;;GAGG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IAExB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAElB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,mBAAmB,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IAEvB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,mBAAmB,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,OAAO,CAAC,CAAC,EACvB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,SAAS,CAAC,CAAC,CAAC,GAC5B,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAEzB"}
|
package/script/mod.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.timebox = timebox;
|
|
4
|
+
const effection_1 = require("effection");
|
|
5
|
+
/**
|
|
6
|
+
* Constrain `operation` to complete within `limitMS` milliseconds
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { timebox } from "@effectionx/timebox";
|
|
11
|
+
* import { handleRequest } from "./handle-request";
|
|
12
|
+
|
|
13
|
+
* // a theoretical request handler
|
|
14
|
+
* export function* handler(request: Request): Operation<Response> {
|
|
15
|
+
* // do not let the handler run for more than 10 seconds
|
|
16
|
+
* let result = yield* timebox(10000, () => handleRequest(request));
|
|
17
|
+
* if (result.timeout) {
|
|
18
|
+
* return new Response(504, "Gateway Timeout");
|
|
19
|
+
* } else {
|
|
20
|
+
* return result.value;
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
* @param limitMS - the maximum allowable time for `operation` to complete
|
|
25
|
+
* @param operation - the operation to attempt
|
|
26
|
+
* @returns either a completed value or a timeout
|
|
27
|
+
*/
|
|
28
|
+
function timebox(limitMS, operation) {
|
|
29
|
+
return (0, effection_1.race)([complete(operation), deadline(limitMS)]);
|
|
30
|
+
}
|
|
31
|
+
function* deadline(limitMS) {
|
|
32
|
+
let start = performance.now();
|
|
33
|
+
yield* (0, effection_1.sleep)(limitMS);
|
|
34
|
+
return { timeout: true, start, end: performance.now() };
|
|
35
|
+
}
|
|
36
|
+
function* complete(op) {
|
|
37
|
+
let start = performance.now();
|
|
38
|
+
return { timeout: false, value: yield* op(), start, end: performance.now() };
|
|
39
|
+
}
|