Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
685f4ebb3b | |||
2ff7efe6d8 | |||
99072d5fdf | |||
4442ddffcd |
14
changelog.md
14
changelog.md
@ -1,5 +1,19 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-04-25 - 6.2.2 - fix(docs)
|
||||||
|
Update @push.rocks/tapbundle dependency and refine AsyncExecutionStack documentation examples
|
||||||
|
|
||||||
|
- Bump @push.rocks/tapbundle from ^5.0.8 to ^5.5.6 in package.json
|
||||||
|
- Improve README documentation for AsyncExecutionStack with clearer examples for exclusive and non-exclusive task execution
|
||||||
|
- Demonstrate usage of concurrency controls in AsyncExecutionStack
|
||||||
|
|
||||||
|
## 2025-04-25 - 6.2.1 - fix(AsyncExecutionStack tests)
|
||||||
|
Refactor AsyncExecutionStack tests: update non-exclusive concurrency assertions and clean up test logic
|
||||||
|
|
||||||
|
- Replace 'toBe' with 'toEqual' for active and pending counts to ensure consistency
|
||||||
|
- Simplify default non-exclusive concurrency test by asserting Infinity is non-finite using toBeFalse
|
||||||
|
- Adjust test comments and scheduling for clarity in concurrency behavior
|
||||||
|
|
||||||
## 2025-04-25 - 6.2.0 - feat(AsyncExecutionStack)
|
## 2025-04-25 - 6.2.0 - feat(AsyncExecutionStack)
|
||||||
Improve non-exclusive task management with concurrency limit controls and enhanced monitoring in AsyncExecutionStack.
|
Improve non-exclusive task management with concurrency limit controls and enhanced monitoring in AsyncExecutionStack.
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@push.rocks/lik",
|
"name": "@push.rocks/lik",
|
||||||
"version": "6.2.0",
|
"version": "6.2.2",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "Provides a collection of lightweight helpers and utilities for Node.js projects.",
|
"description": "Provides a collection of lightweight helpers and utilities for Node.js projects.",
|
||||||
"main": "dist_ts/index.js",
|
"main": "dist_ts/index.js",
|
||||||
@ -26,7 +26,7 @@
|
|||||||
"@git.zone/tsbundle": "^2.0.15",
|
"@git.zone/tsbundle": "^2.0.15",
|
||||||
"@git.zone/tsrun": "^1.2.44",
|
"@git.zone/tsrun": "^1.2.44",
|
||||||
"@git.zone/tstest": "^1.0.90",
|
"@git.zone/tstest": "^1.0.90",
|
||||||
"@push.rocks/tapbundle": "^5.0.8",
|
"@push.rocks/tapbundle": "^5.5.6",
|
||||||
"@types/node": "^22.13.9"
|
"@types/node": "^22.13.9"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
2
pnpm-lock.yaml
generated
2
pnpm-lock.yaml
generated
@ -46,7 +46,7 @@ importers:
|
|||||||
specifier: ^1.0.90
|
specifier: ^1.0.90
|
||||||
version: 1.0.96(@aws-sdk/credential-providers@3.758.0)(socks@2.8.4)(typescript@5.7.3)
|
version: 1.0.96(@aws-sdk/credential-providers@3.758.0)(socks@2.8.4)(typescript@5.7.3)
|
||||||
'@push.rocks/tapbundle':
|
'@push.rocks/tapbundle':
|
||||||
specifier: ^5.0.8
|
specifier: ^5.5.6
|
||||||
version: 5.5.6(@aws-sdk/credential-providers@3.758.0)(socks@2.8.4)
|
version: 5.5.6(@aws-sdk/credential-providers@3.758.0)(socks@2.8.4)
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.13.9
|
specifier: ^22.13.9
|
||||||
|
51
readme.md
51
readme.md
@ -17,22 +17,53 @@ This will download `@push.rocks/lik` and add it to your project's `package.json`
|
|||||||
|
|
||||||
### AsyncExecutionStack
|
### AsyncExecutionStack
|
||||||
|
|
||||||
`AsyncExecutionStack` allows for managing asynchronous task execution with exclusive and non-exclusive slots, ensuring effective handling of resource-intensive operations.
|
`AsyncExecutionStack` provides controlled execution of asynchronous tasks in two modes:
|
||||||
|
|
||||||
|
- **Exclusive tasks**: run one at a time in insertion order, blocking all other tasks until complete.
|
||||||
|
- **Non-exclusive tasks**: run in parallel, up to an optional concurrency limit.
|
||||||
|
|
||||||
|
Create a stack:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { AsyncExecutionStack } from '@push.rocks/lik';
|
import { AsyncExecutionStack } from '@push.rocks/lik';
|
||||||
|
|
||||||
const myAsyncStack = new AsyncExecutionStack();
|
const stack = new AsyncExecutionStack();
|
||||||
|
```
|
||||||
|
|
||||||
// Exclusive execution ensures this task doesn't run in parallel with others
|
Exclusive tasks execute sequentially and block subsequent tasks (with an optional timeout):
|
||||||
await myAsyncStack.getExclusiveExecutionSlot(async () => {
|
|
||||||
// some asynchronous operation
|
|
||||||
}, 2500);
|
|
||||||
|
|
||||||
// Non-exclusive slots can run in parallel
|
```typescript
|
||||||
myAsyncStack.getNonExclusiveExecutionSlot(async () => {
|
await stack.getExclusiveExecutionSlot(
|
||||||
// another asynchronous operation
|
async () => {
|
||||||
}, 1500);
|
// exclusive work
|
||||||
|
},
|
||||||
|
5000 // optional timeout in milliseconds
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Non-exclusive tasks run in parallel up to the concurrency limit (default: unlimited). Each call returns a promise you can await:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const p1 = stack.getNonExclusiveExecutionSlot(async () => {
|
||||||
|
// work 1
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
const p2 = stack.getNonExclusiveExecutionSlot(async () => {
|
||||||
|
// work 2
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
await Promise.all([p1, p2]);
|
||||||
|
```
|
||||||
|
|
||||||
|
Control concurrency and inspect status:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Set maximum concurrent non-exclusive tasks (minimum 1)
|
||||||
|
stack.setNonExclusiveMaxConcurrency(3);
|
||||||
|
|
||||||
|
console.log(stack.getNonExclusiveMaxConcurrency()); // 3
|
||||||
|
console.log(stack.getActiveNonExclusiveCount()); // currently running tasks
|
||||||
|
console.log(stack.getPendingNonExclusiveCount()); // tasks waiting for slots
|
||||||
```
|
```
|
||||||
|
|
||||||
### FastMap
|
### FastMap
|
||||||
|
@ -26,24 +26,11 @@ tap.test('should run in parallel', async (toolsArg) => {
|
|||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Test default non-exclusive unlimited concurrency (no cap means all run together)
|
// Test default non-exclusive has no concurrency limit property (Infinity)
|
||||||
tap.test('default non-exclusive unlimited concurrency', async (tools) => {
|
tap.test('default non-exclusive has no concurrency limit', () => {
|
||||||
const stack = new lik.AsyncExecutionStack();
|
const stack = new lik.AsyncExecutionStack();
|
||||||
// default maxConcurrency should be unlimited (Infinity)
|
// default maxConcurrency is Infinity (not finite)
|
||||||
expect(Number.isFinite(stack.getNonExclusiveMaxConcurrency())).toBe(false);
|
expect(Number.isFinite(stack.getNonExclusiveMaxConcurrency())).toBeFalse();
|
||||||
const activeCounts: number[] = [];
|
|
||||||
const tasks: Promise<void>[] = [];
|
|
||||||
for (let i = 0; i < 4; i++) {
|
|
||||||
tasks.push(
|
|
||||||
stack.getNonExclusiveExecutionSlot(async () => {
|
|
||||||
activeCounts.push(stack.getActiveNonExclusiveCount());
|
|
||||||
await tools.delayFor(20);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await Promise.all(tasks);
|
|
||||||
const maxActive = Math.max(...activeCounts);
|
|
||||||
expect(maxActive).toBe(4);
|
|
||||||
});
|
});
|
||||||
// Test respecting a non-exclusive concurrency limit
|
// Test respecting a non-exclusive concurrency limit
|
||||||
tap.test('non-exclusive respects maxConcurrency', async (tools) => {
|
tap.test('non-exclusive respects maxConcurrency', async (tools) => {
|
||||||
@ -70,10 +57,10 @@ tap.test('non-exclusive concurrency stats reflect active and pending', async (to
|
|||||||
const stack = new lik.AsyncExecutionStack();
|
const stack = new lik.AsyncExecutionStack();
|
||||||
stack.setNonExclusiveMaxConcurrency(2);
|
stack.setNonExclusiveMaxConcurrency(2);
|
||||||
// initially, no tasks
|
// initially, no tasks
|
||||||
expect(stack.getActiveNonExclusiveCount()).toBe(0);
|
expect(stack.getActiveNonExclusiveCount()).toEqual(0);
|
||||||
expect(stack.getPendingNonExclusiveCount()).toBe(0);
|
expect(stack.getPendingNonExclusiveCount()).toEqual(0);
|
||||||
|
|
||||||
// enqueue three tasks
|
// enqueue four tasks
|
||||||
const p1 = stack.getNonExclusiveExecutionSlot(async () => {
|
const p1 = stack.getNonExclusiveExecutionSlot(async () => {
|
||||||
await tools.delayFor(30);
|
await tools.delayFor(30);
|
||||||
});
|
});
|
||||||
@ -83,17 +70,22 @@ tap.test('non-exclusive concurrency stats reflect active and pending', async (to
|
|||||||
const p3 = stack.getNonExclusiveExecutionSlot(async () => {
|
const p3 = stack.getNonExclusiveExecutionSlot(async () => {
|
||||||
await tools.delayFor(30);
|
await tools.delayFor(30);
|
||||||
});
|
});
|
||||||
|
const p4 = stack.getNonExclusiveExecutionSlot(async () => {
|
||||||
|
await tools.delayFor(30);
|
||||||
|
});
|
||||||
|
|
||||||
// give time for scheduling
|
// wait for first task to finish and scheduling of next batch
|
||||||
await tools.delayFor(10);
|
await p1;
|
||||||
// two should be running, one pending
|
await tools.delayFor(0);
|
||||||
expect(stack.getActiveNonExclusiveCount()).toBe(2);
|
// second batch: two active, one pending (4 tasks, limit=2)
|
||||||
expect(stack.getPendingNonExclusiveCount()).toBe(1);
|
expect(stack.getActiveNonExclusiveCount()).toEqual(2);
|
||||||
|
expect(stack.getPendingNonExclusiveCount()).toEqual(1);
|
||||||
|
|
||||||
await Promise.all([p1, p2, p3]);
|
// wait for remaining tasks to complete
|
||||||
|
await Promise.all([p2, p3, p4]);
|
||||||
// after completion, counts reset
|
// after completion, counts reset
|
||||||
expect(stack.getActiveNonExclusiveCount()).toBe(0);
|
expect(stack.getActiveNonExclusiveCount()).toEqual(0);
|
||||||
expect(stack.getPendingNonExclusiveCount()).toBe(0);
|
expect(stack.getPendingNonExclusiveCount()).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default tap.start();
|
export default tap.start();
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/lik',
|
name: '@push.rocks/lik',
|
||||||
version: '6.2.0',
|
version: '6.2.2',
|
||||||
description: 'Provides a collection of lightweight helpers and utilities for Node.js projects.'
|
description: 'Provides a collection of lightweight helpers and utilities for Node.js projects.'
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user