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: allow setting a timeout for mysql try lock #1200

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions database/mysql/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
| `x-migrations-table` | `MigrationsTable` | Name of the migrations table |
| `x-no-lock` | `NoLock` | Set to `true` to skip `GET_LOCK`/`RELEASE_LOCK` statements. Useful for [multi-master MySQL flavors](https://www.percona.com/doc/percona-xtradb-cluster/LATEST/features/pxc-strict-mode.html#explicit-table-locking). Only run migrations from one host when this is enabled. |
| `x-statement-timeout` | `StatementTimeout` | Abort any statement that takes more than the specified number of milliseconds, functionally similar to [Server-side SELECT statement timeouts](https://dev.mysql.com/blog-archive/server-side-select-statement-timeouts/) but enforced by the client. Available for all versions of MySQL, not just >=5.7. |
| `x-try-lock-timeout` | `TryLockTimeoutSec` | Timeout in seconds to try to obtain migrations lock. A negative value means infinite timeout. Default value is `10` |
| `dbname` | `DatabaseName` | The name of the database to connect to |
| `user` | | The user to sign in as |
| `password` | | The user's password |
Expand Down
38 changes: 28 additions & 10 deletions database/mysql/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ func init() {
database.Register("mysql", &Mysql{})
}

const DefaultTryLockTimeoutSec = 10

var DefaultMigrationsTable = "schema_migrations"

var (
Expand All @@ -40,10 +42,11 @@ var (
)

type Config struct {
MigrationsTable string
DatabaseName string
NoLock bool
StatementTimeout time.Duration
MigrationsTable string
DatabaseName string
NoLock bool
StatementTimeout time.Duration
TryLockTimeoutSec int
}

type Mysql struct {
Expand Down Expand Up @@ -253,16 +256,26 @@ func (m *Mysql) Open(url string) (database.Driver, error) {
}
}

tryLockTimeoutParam := customParams["x-try-lock-timeout"]
tryLockTimeout := DefaultTryLockTimeoutSec
if tryLockTimeoutParam != "" {
tryLockTimeout, err = strconv.Atoi(tryLockTimeoutParam)
if err != nil {
return nil, fmt.Errorf("could not parse x-try-lock-timeout as int: %w", err)
}
}

db, err := sql.Open("mysql", config.FormatDSN())
if err != nil {
return nil, err
}

mx, err := WithInstance(db, &Config{
DatabaseName: config.DBName,
MigrationsTable: customParams["x-migrations-table"],
NoLock: noLock,
StatementTimeout: time.Duration(statementTimeout) * time.Millisecond,
DatabaseName: config.DBName,
MigrationsTable: customParams["x-migrations-table"],
NoLock: noLock,
StatementTimeout: time.Duration(statementTimeout) * time.Millisecond,
TryLockTimeoutSec: tryLockTimeout,
})
if err != nil {
return nil, err
Expand Down Expand Up @@ -295,9 +308,14 @@ func (m *Mysql) Lock() error {
return err
}

query := "SELECT GET_LOCK(?, 10)"
tryLockTimeout := DefaultTryLockTimeoutSec
if m.config.TryLockTimeoutSec != 0 {
tryLockTimeout = m.config.TryLockTimeoutSec
}

query := "SELECT GET_LOCK(?, ?)"
var success bool
if err := m.conn.QueryRowContext(context.Background(), query, aid).Scan(&success); err != nil {
if err := m.conn.QueryRowContext(context.Background(), query, aid, tryLockTimeout).Scan(&success); err != nil {
return &database.Error{OrigErr: err, Err: "try lock failed", Query: []byte(query)}
}

Expand Down
Loading