Compare commits
2 commits
a5c1abbbed
...
3c2ef378bc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c2ef378bc | ||
|
|
ff2e135d72 |
8 changed files with 1208 additions and 13 deletions
2
.helix/ignore
Normal file
2
.helix/ignore
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
12
.helix/languages.toml
Normal file
12
.helix/languages.toml
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
[[language]]
|
||||||
|
name = "typescript"
|
||||||
|
scope = "source.ts"
|
||||||
|
injection-regex = "(ts|typescript)"
|
||||||
|
language-id = "typescript"
|
||||||
|
file-types = ["ts", "mts", "cts"]
|
||||||
|
shebangs = ["deno", "bun", "ts-node"]
|
||||||
|
roots = [ "package.json", "tsconfig.json" ]
|
||||||
|
comment-token = "//"
|
||||||
|
block-comment-tokens = { start = "/*", end = "*/" }
|
||||||
|
language-servers = [ "typescript-language-server", "vscode-eslint-language-server" ]
|
||||||
|
indent = { tab-width = 2, unit = " " }
|
||||||
14
eslint.config.ts
Normal file
14
eslint.config.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import js from "@eslint/js";
|
||||||
|
import globals from "globals";
|
||||||
|
import tseslint from "typescript-eslint";
|
||||||
|
import { defineConfig } from "eslint/config";
|
||||||
|
|
||||||
|
export default defineConfig([
|
||||||
|
{
|
||||||
|
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
|
||||||
|
plugins: { js },
|
||||||
|
extends: ["js/recommended"],
|
||||||
|
languageOptions: { globals: { ...globals.browser, ...globals.node } },
|
||||||
|
},
|
||||||
|
tseslint.configs.recommended,
|
||||||
|
]);
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
[tools]
|
[tools]
|
||||||
node = "24"
|
node = "24"
|
||||||
|
|
||||||
|
[tasks.lint]
|
||||||
|
run = "npx tsc --noEmit && npx eslint ./src"
|
||||||
|
|
||||||
[tasks.build]
|
[tasks.build]
|
||||||
run = "npx rollup -c"
|
run = "npx rollup -c"
|
||||||
|
|
||||||
[tasks.test]
|
[tasks.test]
|
||||||
|
depends = ["lint"]
|
||||||
run = "npx jest"
|
run = "npx jest"
|
||||||
|
|
|
||||||
1168
package-lock.json
generated
1168
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -17,13 +17,18 @@
|
||||||
"test": "mise run test"
|
"test": "mise run test"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^9.39.2",
|
||||||
"@rollup/plugin-terser": "^0.4.4",
|
"@rollup/plugin-terser": "^0.4.4",
|
||||||
"@rollup/plugin-typescript": "^12.3.0",
|
"@rollup/plugin-typescript": "^12.3.0",
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
|
"eslint": "^9.39.2",
|
||||||
|
"globals": "^17.3.0",
|
||||||
"jest": "^30.2.0",
|
"jest": "^30.2.0",
|
||||||
|
"jiti": "^2.6.1",
|
||||||
"rollup": "^4.57.1",
|
"rollup": "^4.57.1",
|
||||||
"ts-jest": "^29.4.6",
|
"ts-jest": "^29.4.6",
|
||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3",
|
||||||
|
"typescript-eslint": "^8.54.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { AsyncTaskQueue } from "./index";
|
||||||
|
|
||||||
test("example evaluates correctly", async () => {
|
test("example evaluates correctly", async () => {
|
||||||
const q = new AsyncTaskQueue<number>(
|
const q = new AsyncTaskQueue<number>(
|
||||||
async (nums: number[]) => {/* no-op */},
|
async () => {/* no-op */},
|
||||||
)
|
)
|
||||||
// Handler will receive up to 4 items per batch.
|
// Handler will receive up to 4 items per batch.
|
||||||
.batchSize(4)
|
.batchSize(4)
|
||||||
|
|
|
||||||
12
src/index.ts
12
src/index.ts
|
|
@ -3,7 +3,7 @@
|
||||||
*/
|
*/
|
||||||
export class AsyncTaskQueue<T> {
|
export class AsyncTaskQueue<T> {
|
||||||
private _queue: T[] = [];
|
private _queue: T[] = [];
|
||||||
private readonly _handler: (item: T) => Promise<unknown>;
|
private readonly _handler: (items: T[]) => Promise<unknown>;
|
||||||
private _errorHandler: (err: unknown) => unknown = console.error;
|
private _errorHandler: (err: unknown) => unknown = console.error;
|
||||||
private _batchSize = 1;
|
private _batchSize = 1;
|
||||||
private _throttleIntervalMs = 0;
|
private _throttleIntervalMs = 0;
|
||||||
|
|
@ -48,7 +48,7 @@ export class AsyncTaskQueue<T> {
|
||||||
* This method updates the queue in place and returns it, so method calls may
|
* This method updates the queue in place and returns it, so method calls may
|
||||||
* be chained.
|
* be chained.
|
||||||
*/
|
*/
|
||||||
throttleMs(intervalMs?: number): AsyncTaskQueue<T> {
|
throttleMs(intervalMs: number): AsyncTaskQueue<T> {
|
||||||
if (intervalMs < 0) {
|
if (intervalMs < 0) {
|
||||||
throw new Error("Interval must be zero or more milliseconds.");
|
throw new Error("Interval must be zero or more milliseconds.");
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +82,7 @@ export class AsyncTaskQueue<T> {
|
||||||
return this._queue.length;
|
return this._queue.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _processAll(): void {
|
private async _processAll(): Promise<void> {
|
||||||
// Control loop is very simple: a `while` loop in a single async "thread",
|
// Control loop is very simple: a `while` loop in a single async "thread",
|
||||||
// which runs until the queue is empty and then waits for
|
// which runs until the queue is empty and then waits for
|
||||||
// `this._processAll()` to be called again. Because the execution
|
// `this._processAll()` to be called again. Because the execution
|
||||||
|
|
@ -114,13 +114,13 @@ export class AsyncTaskQueue<T> {
|
||||||
/**
|
/**
|
||||||
* Wraps an arbitrary async function with retry logic for exceptions.
|
* Wraps an arbitrary async function with retry logic for exceptions.
|
||||||
*/
|
*/
|
||||||
export function withRetry<T, U extends Promise>(
|
export function withRetry<T extends unknown[], U>(
|
||||||
fn: (...args: T) => U,
|
fn: (...args: T) => Promise<U>,
|
||||||
{ attempts = 6, backoffMs = (attempt) => 1000 * 2 ** attempt }: {
|
{ attempts = 6, backoffMs = (attempt) => 1000 * 2 ** attempt }: {
|
||||||
attempts: number;
|
attempts: number;
|
||||||
backoffMs(attempt: number): number;
|
backoffMs(attempt: number): number;
|
||||||
},
|
},
|
||||||
): (...args: T) => U {
|
): (...args: T) => Promise<U> {
|
||||||
return async (...args: T) => {
|
return async (...args: T) => {
|
||||||
for (let attempt = 0; attempt < attempts - 1; attempt += 1) {
|
for (let attempt = 0; attempt < attempts - 1; attempt += 1) {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue