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

feat(jest-worker)!: replace Worker class export with createWorkerFarm() factory function #12680

Closed
wants to merge 16 commits into from

Conversation

mrazauskas
Copy link
Contributor

Part of #12274

Summary

Here is an attempt to replace Worker class exported from jest-worker with an async createWorkerFarm() factory function. This is needed to allow worker modules in ESM syntax.

The createWorkerFarm() function is implemented – it simply does some validation and returns and instance of WorkerFarm class. I have spend some time to make TypeScript usage smoother.

I managed to reshape jest-worker's implementation in jest-reporters and jest-runner, but got stuck with jest-haste-map. Will try again, not giving up yet (;

Test plan

Unit tests and type tests are added. All must pass.

* processed by the same worker. This is specially useful if your workers
* are caching results.
*/
export default class WorkerFarm {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simply moved from index.ts to this file. Nothing much changed.


export type JestWorkerFarm<T> = WorkerFarm & WorkerModule<T>;

const reservedKeys = ['end', 'getStderr', 'getStdout', 'setup', 'teardown'];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently setup() and teardown() are not excluded. Felt like these should not be present in the returned API.

const reservedKeys = ['end', 'getStderr', 'getStdout', 'setup', 'teardown'];

const isReserved = (methodName: string) => reservedKeys.includes(methodName);
const isPrivate = (methodName: string) => methodName.startsWith('_');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a module is exporting a method, it is hardly private. Methods prefix with _ are currently excluded, I just left this in place.

* processed by the same worker. This is specially useful if your workers
* are caching results.
*/
export class Worker {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved it to separate WorkerFarm.ts file to keep index.ts cleaner.

[K in keyof T as Extract<
ExcludeReservedKeys<K>,
MethodLikeKeys<T>
>]: T[K] extends FunctionLike ? Promisify<T[K]> : never;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Methods in the resulting API always return a Promise.

Copy link
Member

@SimenB SimenB left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great stuff!

if (!this._worker) {
if ((options && options.forceInBand) || this._options.maxWorkers <= 1) {
this._worker = {getSha1, worker};
} else {
// @ts-expect-error: assignment of a worker with custom properties.
this._worker = new Worker(require.resolve('./worker'), {
this._worker = new WorkerFarm(require.resolve('./worker'), {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not createWorkerFarm?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. Still struggling with this one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SimenB I was trying again to make this work, but cannot figure out how to make async function work in sync context. Probably some .then should be used to unwrap the promise. Might work, but this function already returns worker() that returns a Promise:

https://github.com/facebook/jest/blob/2f4340cb1da435a9b147e238f7034f99653b8070/packages/jest-haste-map/src/index.ts#L649-L658

I was trying to play with .thens and to refactor this code to use async / await. Unfortunately it is too complex for me. Can’t make it work. Someone more experienced should take a take over this PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cannot figure out how to make async function work in sync context.

Why/where does it have to work in sync context? If it's just https://github.com/facebook/jest/blob/8ef4d86f14954277394c7e4fb708697dfa92e80c/packages/jest-haste-map/src/index.ts#L743, making that return a Promise seems fine?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, _getWorker can return a Promise. It is called and then is used to handle a Promise return by the worker:

https://github.com/facebook/jest/blob/8ef4d86f14954277394c7e4fb708697dfa92e80c/packages/jest-haste-map/src/index.ts#L652-L661

The return above is is the return of _processFile method, that has a return type of Promise<void> | null:

https://github.com/facebook/jest/blob/8ef4d86f14954277394c7e4fb708697dfa92e80c/packages/jest-haste-map/src/index.ts#L451-L457

This null part is where sync fun begins. It just must be Promise<void> | null, not something like Promise<void | null>, because of these lines:

https://github.com/facebook/jest/blob/8ef4d86f14954277394c7e4fb708697dfa92e80c/packages/jest-haste-map/src/index.ts#L703-L709

I was playing with the filter above for some time with no luck. Might be some deeper refactor is needed.

@mrazauskas mrazauskas marked this pull request as draft April 17, 2022 14:05
@SimenB
Copy link
Member

SimenB commented Apr 20, 2022

@mrazauskas I'm planning to release 28 stable in the next few days (possibly this weekend). Just a heads up 🙂 I plan to have v29 come out when node 17 is EOL in June, so not too far into the future if you wanna wait. No rush either way 👍

@mrazauskas
Copy link
Contributor Author

Sure. I moved forward with refactoring jest-haste-map. That is tricky case. Will figure it out slowly.

@mrazauskas
Copy link
Contributor Author

Oh.. That’s to complicated to rebase and I can’t integrate it with haste module anyways. Leaving this for smarter than me (; Closing to have less noise around.

@mrazauskas mrazauskas closed this Oct 19, 2022
@mrazauskas mrazauskas deleted the feat-createWorkerFarm branch October 19, 2022 12:33
@github-actions
Copy link

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.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 19, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants