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
migrate: Refactor _lockMigrations to avoid forUpdate #3395
Conversation
Since _isLocked is only called just before _lockMigrations, it is redundant and we can accomplish the same thing by checking the rowCount returned by the update (verified by testing with postgres, mysql, sqlite, and mssql). The benefit of this change is improving compatbility with CockroachDB, which does not support FOR UPDATE. Updates knex#2002
_lockMigrations(trx) { | ||
const tableName = getLockTableName(this.config.tableName); | ||
return getTable(this.knex, tableName, this.config.schemaName) | ||
.transacting(trx) | ||
.update({ is_locked: 1 }); | ||
.where('is_locked', '=', 0) |
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.
This does not work. There can be two processes at the same time arriving to this row and both will return one row and both then updates the lock value to 1.
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.
forUpdate exactly causes DB to prevent that from happening.
This approach doesn't work. |
@elhigu Couldn't this be an alternate mechanism that one can opt-in for? Considering that usually migrations are not being executed in same environment concurrently from multiple places, this particular approach is unlikely to cause many real issues in actual production environments for users that may rely on it. |
That would mean basically option for omitting is locked check completely. I'm not against it, but still I would prefer solution, which actually works. I'm pretty sure there must be a way to do something like this that actually works also on CockroachDB |
@elhigu Option to disable lock check might actually be useful. |
In that case those changes that were made to _lockMigrations could be implemented anyways as a secondary safety measure. |
Can you please elaborate on when exactly this fails? I still believe it works, although reasoning about sub-serializable isolation levels is always tricky and under-documented. My informal argument is that in any database that distinguishes between regular There are databases that don't work this way, for example ones that are asynchronously replicated and eventually consistent. My proposal would indeed be incorrect for these systems. However, I've never seen a system like that that has a useful implementation of
One alternative is for the CockroachDB dialect to turn |
Both processes will get the lock and start running migrations parallel.
Hmm... that actually might be true +1 I have never tried that if it really works that way. Only with plain selects and then updating... I'll try it out how it behaves. |
I've added a test, which passes on postgres, mysql, and mssql (it doesn't work on sqlite because it doesn't support concurrent transactions anyway). I followed the existing promises-and-callback style but it would be simpler if it's OK to introduce async/await into this file. |
@bdarnell By all means feel free to use async-await! Promise chains are just legacy. |
@bdarnell Can you take a look at plethora of failures in https://travis-ci.org/tgriesser/knex/jobs/576541045? Something fishy is going on there. |
This is the root cause, and then because we failed to clean up in the The failures are all on the Node 8 job; that version of node must be using a version of Promise that doesn't have the |
@bdarnell Yup, that seems to be it. |
Alright, I've updated this to use async/await and we'll see if it passes CI. Thanks for offering to delay the release. FYI, this won't get us complete cockroachdb compatibility, but it's the main thing I've seen so far that can't be worked around at the dialect level. |
@bdarnell Appreciate the time spent on this! |
Will cut a new release today. |
Since _isLocked is only called just before _lockMigrations, it is redundant
and we can accomplish the same thing by checking the rowCount returned
by the update (verified by testing with postgres, mysql, sqlite, and
mssql).
The benefit of this change is improving compatbility with CockroachDB,
which does not support FOR UPDATE.
Updates #2002