sequelize icon indicating copy to clipboard operation
sequelize copied to clipboard

Parallel executions seems not to update and reload db model properly.

Open Tzvetelin88 opened this issue 3 years ago • 2 comments
trafficstars

Issue Creation Checklist

[x] I have read the contribution guidelines

Issue Description

Payload for the execution:

let payload = {
  "group": {
    "tasks": [
      {
        "name": "Task 1 Name",
        "id": "1"
      },
      {
        "name": "Task 2 Name",
        "id": "2"
      },
      {
        "name": "Task 3 Name",
        "id": "3"
      },
      {
        "name": "Task 4 Name",
        "id": "4"
      }
    ]
  }
}

When running parallel execution by doing this:

await Promise.all(
  group.tasks.map((task: any) =>
    runTask(task)
  )
); 

where "runTask" is:

// getting existing ID's from DB, let assume bellow object as data.
let exeistingIds = {a:1,b:2}

await executorModel.update({
  id: {
      ...exeistingIds,
      [`${this.payload.id}`]: executionId,
    },
  });
await executorModel.reload();

Problem is when we have parallel executions. If we put brake points at:

await executorModel.update

and

await executorModel.reload();

we see that we hit "await executorModel.update" 4 times, and then 4 times "await executorModel.reload()", which leads to wrong information saved to db.

When we have sequential executions, there is no problem. For each task execution we hit "await executorModel.update" 1 time and then we hit "await executorModel.reload()" one time, and continues.

Issue Template Checklist

Is this issue dialect-specific?

  • [x] No. This issue is relevant to Sequelize as a whole.
  • [ ] Yes. This issue only applies to the following dialect(s): XXX, YYY, ZZZ
  • [ ] I don't know.

Would you be willing to resolve this issue by submitting a Pull Request?

  • [ ] Yes, I have the time and I know how to start.
  • [ ] Yes, I have the time but I don't know how to start, I would need guidance.
  • [ ] No, I don't have the time, although I believe I could do it if I had the time...
  • [x] No, I don't have the time and I wouldn't even know how to start.

Tzvetelin88 avatar Sep 08 '22 15:09 Tzvetelin88

This is related to how asynchronous works.

Do you already try to put reload above update?

fzn0x avatar Sep 08 '22 23:09 fzn0x

Yes, the result is the same. If I add additional async function "await testMe()" before "await executorModel.update", it resolves each task in testMe, but still async function from Sequelize update and reload don't hit properly:

async function testMe() {
  return new Promise((resolve) => {
    console.log(`Task ID: ${this.payload.id}`);
    resolve('');
  });
}

maybe the issue is related to some cache or buffer in Sequelize, or some transaction issue?

Tzvetelin88 avatar Sep 09 '22 07:09 Tzvetelin88

This issue has been automatically marked as stale because it has been open for 14 days without activity. It will be closed if no further activity occurs within the next 14 days. If this is still an issue, just leave a comment or remove the "stale" label. 🙂

github-actions[bot] avatar Sep 24 '22 00:09 github-actions[bot]

I'd need to see more code to be sure but this doesn't look like a sequelize issue. It looks like you might be modifying the same attribute on the same row multiple times in parallel. The operations aren't atomic so you end up with concurrency issues.

The field you modify looks like JSON. Depending on your dialect, you may have SQL functions you can use to add something to your JSON without needing to fetch it first, which would resolve the concurrency issue. In postgres, that would be jsonb_set, not sure about other dialects

ephys avatar Sep 24 '22 05:09 ephys

This issue has been automatically marked as stale because it has been open for 14 days without activity. It will be closed if no further activity occurs within the next 14 days. If this is still an issue, just leave a comment or remove the "stale" label. 🙂

github-actions[bot] avatar Oct 09 '22 00:10 github-actions[bot]