internal/database: back off serialization failure exponentially

When a transaction encounters a serialization failure, retry after
waiting some time, instead of retrying immediately. Double the wait
time on each failure.

Change-Id: I2ca3252182115e78e00048aa229fd16dd427f61c
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/350111
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Julie Qiu <julie@golang.org>
diff --git a/internal/database/database.go b/internal/database/database.go
index 227ff4c..ddfd074 100644
--- a/internal/database/database.go
+++ b/internal/database/database.go
@@ -230,6 +230,7 @@
 	// Retry on serialization failure, up to some max.
 	// See https://www.postgresql.org/docs/11/transaction-iso.html.
 	const maxRetries = 10
+	sleepDur := 125 * time.Millisecond
 	for i := 0; i <= maxRetries; i++ {
 		err = db.transact(ctx, opts, txFunc)
 		if isSerializationFailure(err) {
@@ -238,7 +239,9 @@
 				db.maxRetries = i
 			}
 			db.mu.Unlock()
-			log.Debugf(ctx, "serialization failure; retrying")
+			log.Debugf(ctx, "serialization failure; retrying after %s", sleepDur)
+			time.Sleep(sleepDur)
+			sleepDur *= 2
 			continue
 		}
 		if err != nil {