spanner Read-Write Transactionの冪等性について
spannerのRead-Write Transaction
は失敗した時にライブラリレベルで自動的にリトライされる。(golangの場合)
リトライが走るともう一度BeginTransaction
からやり直して、一からトランザクションを始めることになるため、トランザクションで実行している部分が冪等性を担保できているかどうかを確認する必要がある。
bad
実際にはありえないケースだが、例えばiを0で宣言して1を加算してinsertしたいケースがあるとする。
下記のようなパターンでは、ReadWriteTransaction
がabort等によって再実行された際にi
が再加算される。
冪等になっていないので、iが1にならない(リトライされるごとに2,3,4と増えていく)ことがある。
func write(ctx context.Context, w io.Writer, client *spanner.Client, id uint64) error {
i := 0
_, err := client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanneadWriteTransaction) error {
i++
m := []*spanner.Mutation{
spanner.InsertOrUpdate("test", []string{"id", "i"}, []interface{}{id, i}),
}
return client.Apply(ctx, m)
})
return err
}
good
下記のように何度実行されても大丈夫なように冪等性を担保する必要がある。
func write(ctx context.Context, w io.Writer, client *spanner.Client, id uint64) error {
_, err := client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanneadWriteTransaction) error {
// txn内で初期化
i := 0
i++
m := []*spanner.Mutation{
spanner.InsertOrUpdate("test", []string{"id", "i"}, []interface{}{id, i}),
}
return client.Apply(ctx, m)
})
return err
}