From d6b843a911fce6b5c6ef742381c5d3f0c9377005 Mon Sep 17 00:00:00 2001 From: Dom Hutton Date: Mon, 25 Jul 2022 10:42:49 +0300 Subject: [PATCH 1/3] modify: Add statement timeout query parmeter for MySQL --- database/mysql/README.md | 1 + database/mysql/mysql.go | 33 ++++++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/database/mysql/README.md b/database/mysql/README.md index 096fa5e6b..00aca683d 100644 --- a/database/mysql/README.md +++ b/database/mysql/README.md @@ -6,6 +6,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. | | `dbname` | `DatabaseName` | The name of the database to connect to | | `user` | | The user to sign in as | | `password` | | The user's password | diff --git a/database/mysql/mysql.go b/database/mysql/mysql.go index fef5f44ae..2e8cefede 100644 --- a/database/mysql/mysql.go +++ b/database/mysql/mysql.go @@ -15,6 +15,7 @@ import ( nurl "net/url" "strconv" "strings" + "time" "github.com/go-sql-driver/mysql" "github.com/golang-migrate/migrate/v4/database" @@ -38,9 +39,10 @@ var ( ) type Config struct { - MigrationsTable string - DatabaseName string - NoLock bool + MigrationsTable string + DatabaseName string + NoLock bool + StatementTimeout time.Duration } type Mysql struct { @@ -241,15 +243,25 @@ func (m *Mysql) Open(url string) (database.Driver, error) { } } + statementTimeoutParam := customParams["x-statement-timeout"] + statementTimeout := 0 + if statementTimeoutParam != "" { + statementTimeout, err := strconv.ParseFloat(statementTimeoutParam, 64) + if err != nil { + return nil, fmt.Errorf("could not parse x-statement-timeout as float: %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, + DatabaseName: config.DBName, + MigrationsTable: customParams["x-migrations-table"], + NoLock: noLock, + StatementTimeout: time.Duration(statementTimeout) * time.Millisecond, }) if err != nil { return nil, err @@ -327,8 +339,15 @@ func (m *Mysql) Run(migration io.Reader) error { return err } + ctx := context.Background() + if m.config.StatementTimeout != 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, m.config.StatementTimeout) + defer cancel() + } + query := string(migr[:]) - if _, err := m.conn.ExecContext(context.Background(), query); err != nil { + if _, err := m.conn.ExecContext(ctx, query); err != nil { return database.Error{OrigErr: err, Err: "migration failed", Query: migr} } From f3b58251550213ad45a54e31ded40dfb9ccc45c5 Mon Sep 17 00:00:00 2001 From: Dom Hutton Date: Mon, 25 Jul 2022 08:00:30 +0000 Subject: [PATCH 2/3] fix: parsing and assignment of statementTimeout --- database/mysql/mysql.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/database/mysql/mysql.go b/database/mysql/mysql.go index 2e8cefede..c862e1cc1 100644 --- a/database/mysql/mysql.go +++ b/database/mysql/mysql.go @@ -9,7 +9,6 @@ import ( "crypto/x509" "database/sql" "fmt" - "go.uber.org/atomic" "io" "io/ioutil" nurl "net/url" @@ -17,6 +16,8 @@ import ( "strings" "time" + "go.uber.org/atomic" + "github.com/go-sql-driver/mysql" "github.com/golang-migrate/migrate/v4/database" "github.com/hashicorp/go-multierror" @@ -246,7 +247,7 @@ func (m *Mysql) Open(url string) (database.Driver, error) { statementTimeoutParam := customParams["x-statement-timeout"] statementTimeout := 0 if statementTimeoutParam != "" { - statementTimeout, err := strconv.ParseFloat(statementTimeoutParam, 64) + statementTimeout, err = strconv.Atoi(statementTimeoutParam) if err != nil { return nil, fmt.Errorf("could not parse x-statement-timeout as float: %w", err) } From 9b9df6ebead423fec35b624698824c35782602d6 Mon Sep 17 00:00:00 2001 From: Dom Hutton Date: Wed, 27 Jul 2022 10:59:27 +0000 Subject: [PATCH 3/3] fix: bad merge --- database/mysql/mysql.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/database/mysql/mysql.go b/database/mysql/mysql.go index 40117263e..e0e18e7a9 100644 --- a/database/mysql/mysql.go +++ b/database/mysql/mysql.go @@ -18,8 +18,6 @@ import ( "go.uber.org/atomic" - "go.uber.org/atomic" - "github.com/go-sql-driver/mysql" "github.com/golang-migrate/migrate/v4/database" "github.com/hashicorp/go-multierror"