-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
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
PriorityQueue implementation for jest-worker #10921
Conversation
@MichaReiser @mjesun is this waiting for me? 😅 |
@SimenB would be great if you could take a look at it to get someone else's opinion on the changes and if this is something that would be beneficial for |
I assumed this was some FB thing that you needed and it'd go through without me having to do anything except publishing 😅 From skimming I think this looks good, especially as there's no change in default behavior. And the motivation for the new feature seems sound to me 👍 And of course the improved benchmarks you posted are awesome |
queue.enqueue(createQueueChildMessage({priority})); | ||
} | ||
|
||
priorities.sort((a, b) => a - b); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
priorities.sort((a, b) => a - b); | |
priorities.sort(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The override is required because JavaScript does by default a lexicographical sort.
The sort() method sorts the elements of an array in place and returns the sorted array. The default sort order is ascending, built upon converting the elements into strings, then comparing their sequences of UTF-16 code units values. MDN
[10, 3, 4, 8, 2, 9, 7, 1, 2, 6, 5].sort()
Array(11) [ 1, 10, 2, 2, 3, 4, 5, 6, 7, 8, … ]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JS strikes again 😀
Thanks @SimenB for your thoughtful review!
It did start as part of some work on Metro but then turned out that switching to a priority queue does not improve the performance as much as we hoped for. I then decided to clean up the implementation because in my spare time because I believed the separation of concerns (extracting the task queue) is worth it and a priority queue might come in handy for someone else (or we might need it in the end). |
I resolved the conflicts of this PR and added the changelog entry. Should now be ready to merge. |
Thanks! |
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Summary
The current
jest-worker
implementation processes tasks in FIFO ordering. This assumes that all tasks are equally important which isn't always given.This PR extracts a
TaskQueue
interface, extracts the existing implementation asFifoQueue
, adds a newPriorityQueue
implementations and allows customizing the usedqueue
implementation when creating theJestWorker
.A
TaskQueue
offers two operations:enqueue(workerId: ?number)
: Add a new task to the queue of the specified worker or for all workers if theworkerId
is absentdequeue(workerId: number)
: Return the next task to process for the specified worker id.The
PriorityQueue
uses aMinHeap
that haslog(n)
complexity forenqueue
and O(1) complexity for the dequeue implementation. The implementation uses a shared and n worker specific queues to support sticky workers. The implementation returns the tasks in the ordering according to their priority. Tasks with equal priority are returned in any order except that sticky-tasks are returned before tasks queued in the shared queue.This diff extracts the current queue implementation into the
FifoQueue
class and refactors the implementation to reduce the memory footprint. The current implementation added non-worker specific tasks to the queue of each worker. The result is that there aren * tasks
queue entries wheren
is the number of workers for shared tasks. Furthermore,dequeuing
required to iterate through all tasks from the top until a task that hasn't been processed is found. The refactored implementation uses a shared queue and a separate queue for each worker. Shared tasks are only enqueued in the shared queue. Each task can only be part of one queue making it redundant to find the first non-processed task duringdequeue
.Test plan
Unit tests for the new queue implementations. Existing integration tests pass with the refactored FIFO queue implementation.
Empty
FIFO Current
FIFO Refactored
loadTest
FIFO Current
FIFO Refactored