I'd like input on whether the following idea is good or bad, and why.

Consider an abstract transaction, modeled as follows:
func Transaction(ctx context.Context, body func(ctx context.Context) error)
error
func OnCommit(ctx context.Context, commitHook func(ctx context.Context))
func OnRollback(ctx context.Context, rollbackHook func(ctx context.Context))

The code that wishes to execute a transaction would call Transaction and
provide the body of the transaction as a function parameter.  If that
function returns an error, the transaction is rolled back, by calling any
hooks registered during that transaction by calling OnRollback.  If the
body function returns success, the transaction is committed by calling any
hooks registered during that transaction by calling OnCommit.

The implication of this model is that the identity of what transaction
you're in is stored in the context.  The ctx passed into body has that
value added to it, and the OnCommit and OnRollback calls associate the
hooks with the transaction they find in the context.

Of course the same thing could be done by passing the transaction
explicitly, e.g.
func Transaction(ctx context.Context, body func(ctx context.Context, tx Tx)
error) error
func OnCommit(tx Tx, commitHook func(ctx context.Context))
func OnRollback(tx Tx, rollbackHook func(ctx context.Context))

But this would mean that both ctx and tx would have to be passed in
parameters to all functions called during the body of the transaction.  My
question is whether putting the transaction in the context using
context.WithValue is a reasonable and appropriate use of that mechanism.
If not, why not?

The use case for this transaction model is not really relevant to the
question, but I'll include it for illustrative purposes.  Imagine a web
server implemented in layers, e.g. transport on top of service on top of
database access.  One would like to promote the transaction concept out of
the database access layer so that multiple calls from the service layer to
the database access layer could occur within the same database
transaction.  One way to do that would be to wrap the service call in an
abstract transaction, and have the database layer honor that with database
transactions in an encapsulated fashion.

Many thanks in advance for your reactions and wisdom.
Steve

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to