Skip to content

Commit a3bdfa2

Browse files
committed
add RejectReadOnly
1 parent 382e13d commit a3bdfa2

File tree

3 files changed

+38
-0
lines changed

3 files changed

+38
-0
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,5 @@ Zhenye Xie <xiezhenye at gmail.com>
5959

6060
Barracuda Networks, Inc.
6161
Google Inc.
62+
Keybase Inc.
6263
Stripe Inc.

dsn.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,21 @@ type Config struct {
5454
MultiStatements bool // Allow multiple statements in one query
5555
ParseTime bool // Parse time values to time.Time
5656
Strict bool // Return warnings as errors
57+
58+
// RejectreadOnly causes mysql driver to reject read-only connections. This
59+
// is specifically for AWS Aurora: During a failover, there seems to be a
60+
// race condition on Aurora, where we get connected to the [old master
61+
// before failover], i.e. the [new read-only slave after failover].
62+
//
63+
// Note that this should be a fairly rare case, as automatic failover
64+
// normally happens when master is down, and the race condition shouldn't
65+
// happen unless it comes back up online as soon as the failover is kicked
66+
// off. But it's pretty easy to reproduce using a manual failover. In case
67+
// this happens, we should reconnect to the Aurora cluster by returning a
68+
// driver.ErrBadConnection.
69+
//
70+
// tl;dr: Set this if you are using Aurora.
71+
RejectReadOnly bool
5772
}
5873

5974
// FormatDSN formats the given Config into a DSN string which can be passed to
@@ -195,6 +210,15 @@ func (cfg *Config) FormatDSN() string {
195210
buf.WriteString(cfg.ReadTimeout.String())
196211
}
197212

213+
if cfg.RejectReadOnly {
214+
if hasParam {
215+
buf.WriteString("&rejectReadOnly=true")
216+
} else {
217+
hasParam = true
218+
buf.WriteString("?rejectReadOnly=true")
219+
}
220+
}
221+
198222
if cfg.Strict {
199223
if hasParam {
200224
buf.WriteString("&strict=true")
@@ -472,6 +496,14 @@ func parseDSNParams(cfg *Config, params string) (err error) {
472496
return
473497
}
474498

499+
// Reject read-only connections
500+
case "rejectReadOnly":
501+
var isBool bool
502+
cfg.RejectReadOnly, isBool = readBool(value)
503+
if !isBool {
504+
return errors.New("invalid bool value: " + value)
505+
}
506+
475507
// Strict mode
476508
case "strict":
477509
var isBool bool

packets.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,11 @@ func (mc *mysqlConn) handleErrorPacket(data []byte) error {
551551
// Error Number [16 bit uint]
552552
errno := binary.LittleEndian.Uint16(data[1:3])
553553

554+
// 1792: ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
555+
if errno == 1792 && mc.cfg.RejectReadOnly {
556+
return driver.ErrBadConn
557+
}
558+
554559
pos := 3
555560

556561
// SQL State [optional: # + 5bytes string]

0 commit comments

Comments
 (0)