-
Notifications
You must be signed in to change notification settings - Fork 523
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(experimental): add internal migrate package and SessionLocker interface #606
Conversation
// SessionLocker is the interface to lock and unlock the database for the duration of a session. The | ||
// session is defined as the duration of a single connection and both methods must be called on the | ||
// same connection. | ||
type SessionLocker interface { |
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.
I took the best bits of #575 and ported them into this PR.
Kudos to @roblaszczak for suggesting a common interface so users can bring their own implementation. I think this should suffice? Feedback/suggestions are welcome.
I called this "SessionLocker" with the hopes of one day also adding a "TransactionLocker".
The one gotcha here is supplying a locker that doesn't match up with the correct dialect. I tried to name the functions appropriately, but there's nothing enforcing this right now.
if err := row.Scan(&unlocked); err != nil { | ||
return err | ||
} | ||
if unlocked { |
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.
Could argue this is best effort and goose shouldn't fail if a session cannot be unlocked. Need to think about this scenario a bit more.
This PR doesn't implement the locking / unlocking logic in goose itself, but when we get to that portion, let's make sure to address the feedback in #507 (comment) |
|
||
func (l *postgresSessionLocker) SessionLock(ctx context.Context, conn *sql.Conn) error { | ||
return retry.Do(ctx, l.retryLock, func(ctx context.Context) error { | ||
row := conn.QueryRowContext(ctx, "SELECT pg_try_advisory_lock($1)", l.lockID) |
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.
It's possible someone may want to opt out of retries and prefer a blocking operation like pg_advisory_lock
If another session already holds a lock on the same resource identifier, this function (pg_advisory_lock) will wait until the resource becomes available.
I suppose with an option like lock.WithBlocking
we could extend and add this logic. While keeping the default as pg_try_advisory_lock
with retries.
The alternative is to have a completely different implementation or users just bring their own locker.
This PR stubs out an internal
package migrate
that:This PR also introduces a
package lock
that defines aSessionLocker
interface, with a single postgres implementation that usespg_try_advisory_lock
. The default behaviour remains the same, but this should unlock functionality to address #335The intended usage goes something like:
The one downside is the locker implementation is unaware of the dialect, so someone could accidentally call
NewPostgresSessionLocker
for a non-postgres database.