Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add .setPriority() for updating priority of a queued promise function #209

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a949f8d
#208 - add update priority logic, add promise started event
RaishavHanspal Jul 10, 2024
4cdcbf7
#208 - update for uidAssigner
RaishavHanspal Jul 10, 2024
8383aac
#208 - add test cases, add linting fixes
RaishavHanspal Jul 11, 2024
a60bfc1
#208 - review fixes, remove started event changes
RaishavHanspal Jul 12, 2024
cafe886
#208 - review fixes - add test case, update setPriority method
RaishavHanspal Jul 18, 2024
6a370fe
#208 - throw error if undefined item in queue while setting priority
RaishavHanspal Jul 19, 2024
ccb7a53
#208 - update spacing
RaishavHanspal Jul 19, 2024
686f0d8
#208 - use enqueue function in setPriority
RaishavHanspal Jul 19, 2024
ecc003d
feedback fixes - add test cases, update code comments, update readme
RaishavHanspal Nov 20, 2024
f7aa85a
Update options.ts
sindresorhus Nov 20, 2024
ff4a177
update readme, update comments
RaishavHanspal Nov 21, 2024
6baad95
Merge branch 'feature/update-priority' of https://github.com/RaishavH…
RaishavHanspal Nov 21, 2024
52cbeef
update spacing
RaishavHanspal Nov 21, 2024
a62603c
match doc comment for .setPriority with readme
RaishavHanspal Nov 27, 2024
46965f7
Update readme.md
sindresorhus Dec 3, 2024
ee1ab21
Update index.ts
sindresorhus Dec 3, 2024
33a2d36
Update test.ts
sindresorhus Dec 3, 2024
253d67f
Update index.ts
sindresorhus Dec 4, 2024
4b70ec7
implement review comments - update id to index, few message/comment u…
RaishavHanspal Jan 3, 2025
a0d0812
resolve conflicts
RaishavHanspal Jan 3, 2025
21a7501
revert back index to id
RaishavHanspal Jan 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions source/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsT

readonly #throwOnTimeout: boolean;

/** Use to assign a unique identifier to a promise function, if not explicitly specified */
RaishavHanspal marked this conversation as resolved.
Show resolved Hide resolved
#idAssigner = 1;
RaishavHanspal marked this conversation as resolved.
Show resolved Hide resolved

/**
Per-operation timeout in milliseconds. Operations fulfill once `timeout` elapses if they haven't already.

Expand Down Expand Up @@ -228,12 +231,21 @@ export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsT
});
}

setPriority(id: string, priority: number) {
RaishavHanspal marked this conversation as resolved.
Show resolved Hide resolved
this.#queue.setPriority(id, priority);
}

/**
Adds a sync or async task to the queue. Always returns a promise.
*/
async add<TaskResultType>(function_: Task<TaskResultType>, options: {throwOnTimeout: true} & Exclude<EnqueueOptionsType, 'throwOnTimeout'>): Promise<TaskResultType>;
async add<TaskResultType>(function_: Task<TaskResultType>, options?: Partial<EnqueueOptionsType>): Promise<TaskResultType | void>;
async add<TaskResultType>(function_: Task<TaskResultType>, options: Partial<EnqueueOptionsType> = {}): Promise<TaskResultType | void> {
// Incase id is not defined
RaishavHanspal marked this conversation as resolved.
Show resolved Hide resolved
if (options.id === undefined) {
options.id = (this.#idAssigner++).toString();
}
RaishavHanspal marked this conversation as resolved.
Show resolved Hide resolved

options = {
timeout: this.timeout,
throwOnTimeout: this.#throwOnTimeout,
Expand Down
1 change: 1 addition & 0 deletions source/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export type QueueAddOptions = {
@default 0
*/
readonly priority?: number;
id?: string;
RaishavHanspal marked this conversation as resolved.
Show resolved Hide resolved
RaishavHanspal marked this conversation as resolved.
Show resolved Hide resolved
RaishavHanspal marked this conversation as resolved.
Show resolved Hide resolved
} & TaskOptions & TimeoutOptions;

export type TaskOptions = {
Expand Down
28 changes: 27 additions & 1 deletion source/priority-queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ export default class PriorityQueue implements Queue<RunFunction, PriorityQueueOp

const element = {
priority: options.priority,
id: options.id,
run,
};

if (this.size && this.#queue[this.size - 1]!.priority! >= options.priority!) {
if (this.size === 0 || this.#queue[this.size - 1]!.priority! >= options.priority!) {
this.#queue.push(element);
return;
}
Expand All @@ -32,6 +33,31 @@ export default class PriorityQueue implements Queue<RunFunction, PriorityQueueOp
this.#queue.splice(index, 0, element);
}

setPriority(id: string, priority: number) {
const existingIndex: number = this.#queue.findIndex((element: Readonly<PriorityQueueOptions>) => element.id === id);
RaishavHanspal marked this conversation as resolved.
Show resolved Hide resolved
if (existingIndex === -1) {
throw new Error('Invalid Index - No promise function of specified id available in the queue.');
RaishavHanspal marked this conversation as resolved.
Show resolved Hide resolved
}

const [item] = this.#queue.splice(existingIndex, 1);
RaishavHanspal marked this conversation as resolved.
Show resolved Hide resolved
if (item === undefined) {
return;
RaishavHanspal marked this conversation as resolved.
Show resolved Hide resolved
}
RaishavHanspal marked this conversation as resolved.
Show resolved Hide resolved

item.priority = priority;
if (this.size === 0 || this.#queue[this.size - 1]!.priority! >= priority) {
this.#queue.push(item);
return;
}
RaishavHanspal marked this conversation as resolved.
Show resolved Hide resolved

const index = lowerBound(
this.#queue, item,
(a: Readonly<PriorityQueueOptions>, b: Readonly<PriorityQueueOptions>) => b.priority! - a.priority!,
);

this.#queue.splice(index, 0, item);
}

dequeue(): RunFunction | undefined {
const item = this.#queue.shift();
return item?.run;
Expand Down
1 change: 1 addition & 0 deletions source/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export type Queue<Element, Options> = {
filter: (options: Readonly<Partial<Options>>) => Element[];
dequeue: () => Element | undefined;
enqueue: (run: Element, options?: Partial<Options>) => void;
setPriority: (id: string, priority: number) => void;
};
42 changes: 41 additions & 1 deletion test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import inRange from 'in-range';
import timeSpan from 'time-span';
import randomInt from 'random-int';
import pDefer from 'p-defer';
import PQueue, {AbortError} from '../source/index.js';
import PQueue from '../source/index.js';

const fixture = Symbol('fixture');

Expand Down Expand Up @@ -1134,3 +1134,43 @@ test('aborting multiple jobs at the same time', async t => {
await t.throwsAsync(task2, {instanceOf: DOMException});
t.like(queue, {size: 0, pending: 0});
});

test('.setPriority() - execute a promise before planned', async t => {
const result: string[] = [];
const queue = new PQueue({concurrency: 1});
queue.add(async () => {
await delay(400);
result.push('🐌');
}, {id: '🐌'});
queue.add(async () => {
await delay(400);
result.push('🦆');
}, {id: '🦆'});
queue.add(async () => {
await delay(400);
result.push('🐢');
}, {id: '🐢'});
queue.setPriority('🐢', 1);
await queue.onIdle();
t.deepEqual(result, ['🐌', '🐢', '🦆']);
});

test.failing('.setPriority() - with invalid "id"', async t => {
RaishavHanspal marked this conversation as resolved.
Show resolved Hide resolved
const result: string[] = [];
const queue = new PQueue({concurrency: 1});
queue.add(async () => {
await delay(400);
result.push('🐌');
}, {id: '🐌'});
queue.add(async () => {
await delay(400);
result.push('🦆');
}, {id: '🦆'});
queue.add(async () => {
await delay(400);
result.push('🐢');
}, {id: '🐢'});
queue.setPriority('⚡️', 1);
await queue.onIdle();
t.deepEqual(result, ['🐌', '🐢', '🦆']);
});