Your Question

How should WithContext be combined with Transaction? I'm particularly thinking about reacting to a cancelation.

3 options I can see:

  1. Use it for both. My guess is this does nothing over (2)
func Do(ctx context.Context, db *gorm.DB) error {
  return db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
    for i := 0; i < 5; i++ {
      if err := tx.WithContext(ctx).Query(...).Error; err != nil {
        return err
      }
    }
  }
}
  1. Use it at the top-level before initiating the transaction, but not within the tx. I'm guessing the context trickles down so this would be the way to do it?
func Do(ctx context.Context, db *gorm.DB) error {
  return db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
    for i := 0; i < 5; i++ {
      if err := tx.Query(...).Error; err != nil {
        return err
      }
    }
  }
}
  1. Skip it at the top-level and use it in each transaction sub-query. If my above guess is correct, then I think this accomplishes the same thing as (2), while requiring more effort at runtime.
func Do(ctx context.Context, db *gorm.DB) error {
  return db.Transaction(func(tx *gorm.DB) error {
    for i := 0; i < 5; i++ {
      if err := tx.WithContext(ctx).Query(...).Error; err != nil {
        return err
      }
    }
  }
}

The document you expected this should be explained

Transactions and maybe Context

Expected answer

A recommendation as to which style is the most appropriate with dealing with contexts, particularly for responding to cancelations. If there's a reason to use one over the other, pro/con would be handy.

Comment From: black-06

Yes, No.2 is ok.

db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
// ...
})

Context is stored in Statement, so db and tx hold the same ctx

Comment From: jessdwitch

That's what I thought, but I appreciate the confirmation. Thank you!