thoughtbot / fishery

A library for setting up JavaScript objects as test data
MIT License
876 stars 36 forks source link

Workaround for Deadlock or sequence uniqueness problem #92

Closed romeerez closed 2 years ago

romeerez commented 2 years ago

I was facing a Deadlock errors in tests, how to achieve it:

I didn't encounter uniqueness problem because all tests are running in own transactions in my setup, but instead I had Deadlock errors because different transactions are operating with records with the same ids.

And here is simple workaround for Jest:

const jestWorkerId = parseInt(process.env.JEST_WORKER_ID as string);
if (!jestWorkerId) {
  throw new Error('Cannot get JEST_WORKER_ID env variable');
}

const idsDistanceBetweenWorkers = 1000;

Object.assign(Factory.prototype, {
  sequence(this: { id: { value: number } }) {
    // id starts from 1 in fishery
    if (this.id.value === 1) {
      this.id.value = jestWorkerId * idsDistanceBetweenWorkers;
    }

    return this.id.value++;
  },
});

Jest provides JEST_WORKER_ID starting from 0 which means index of current running in parallel test

I monkey-patched sequence method to start from 0 for first worker, from 1000 for second worker, from 2000 for third and so on.

Hope this can help someone

I propose to change SEQUENCE_START_VALUE constant to be a public field of Factory so it can be set without monkey-patching

romeerez commented 2 years ago

This must be a simple change to expose the constant and add some info to readme, I could try to make PR for this, are PRs welcome, do you agree with exposing this constant?

stevehanson commented 2 years ago

Hi @romeerez. Since i haven't received any other requests for this feature, and since you have found a workaround, I am going to close this issue as something we will not fix for now.

You can always work around the sequence issue in your case by using the Jest worker ID in the specific places you use the sequence, as opposed to modifying the sequence itself through monkey patching. Example:


const buildId = (sequence: number) => {
  const jestWorkerId = parseInt(process.env.JEST_WORKER_ID as string);
  return jestWorkerId * 1000 + sequence
}

const myFactory = Factory.define(({ sequence }) => ({
  id: buildId(sequence)
});