in db/ref.go [245:284]
func (r *Ref) Transaction(ctx context.Context, fn UpdateFn) error {
req := &internal.Request{
Method: http.MethodGet,
Opts: []internal.HTTPOption{
internal.WithHeader("X-Firebase-ETag", "true"),
},
}
resp, err := r.sendAndUnmarshal(ctx, req, nil)
if err != nil {
return err
}
etag := resp.Header.Get("Etag")
for i := 0; i < txnRetries; i++ {
new, err := fn(&transactionNodeImpl{resp.Body})
if err != nil {
return err
}
req := &internal.Request{
Method: http.MethodPut,
Body: internal.NewJSONEntity(new),
Opts: []internal.HTTPOption{
internal.WithHeader("If-Match", etag),
},
SuccessFn: successOrPreconditionFailed,
}
resp, err = r.sendAndUnmarshal(ctx, req, nil)
if err != nil {
return err
}
if resp.Status == http.StatusOK {
return nil
}
etag = resp.Header.Get("ETag")
}
return fmt.Errorf("transaction aborted after failed retries")
}