Nothing special: just add comments to the BeginTransaction, I have more ideas on this, stay tuned

This commit is contained in:
Gerasimos (Makis) Maropoulos 2016-12-18 13:24:24 +02:00
parent f54dc697cc
commit 1da8231abd

View File

@ -16,6 +16,7 @@ import (
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
"github.com/iris-contrib/formBinder" "github.com/iris-contrib/formBinder"
@ -1177,6 +1178,21 @@ type TransactionScope struct {
isFailure bool isFailure bool
} }
var tspool = sync.Pool{New: func() interface{} { return &TransactionScope{} }}
func acquireTransactionScope(ctx *Context) *TransactionScope {
ts := tspool.Get().(*TransactionScope)
ts.Context = ctx
return ts
}
func releaseTransactionScope(ts *TransactionScope) {
ts.Context = nil
ts.isFailure = false
ts.isRequestScoped = false
tspool.Put(ts)
}
// RequestScoped receives a boolean which determinates if other transactions depends on this. // RequestScoped receives a boolean which determinates if other transactions depends on this.
// If setted true then whenever this transaction is not completed succesfuly, // If setted true then whenever this transaction is not completed succesfuly,
// the rest of the transactions will be not executed at all. // the rest of the transactions will be not executed at all.
@ -1293,20 +1309,33 @@ func (pipe TransactionFunc) ToMiddleware() HandlerFunc {
// See https://github.com/iris-contrib/examples/tree/master/transactions for more // See https://github.com/iris-contrib/examples/tree/master/transactions for more
func (ctx *Context) BeginTransaction(pipe TransactionFunc) { func (ctx *Context) BeginTransaction(pipe TransactionFunc) {
// do NOT begin a transaction when the previous transaction has been failed // do NOT begin a transaction when the previous transaction has been failed
// and it was requested scoped or SkipTransactions called manually // and it was requested scoped or SkipTransactions called manually.
if ctx.TransactionsSkipped() { if ctx.TransactionsSkipped() {
return return
} }
// not the best way but this should be do the job if we want multiple transaction in the same handler and context.
tempCtx := *ctx // clone the temp context
scope := &TransactionScope{Context: &tempCtx}
pipe(scope) // run the context inside its scope
*ctx = *scope.Context // copy back the context
// hold the temp context which will be appear and ready-to-use from the pipe.
tempCtx := *ctx
// get a transaction scope from the pool by passing the temp context/
scope := acquireTransactionScope(&tempCtx)
// run the worker with its context inside this scope.
pipe(scope)
// if the transaction completed with an error then the transaction itself reverts the changes
// and replaces the context's response with an error.
// if the transaction completed successfully then we need to pass the temp's context's response to this context.
// so we must copy back its context at all cases, no matter the result of the transaction.
*ctx = *scope.Context
// if the scope had lifetime of the whole request and it completed with an error(failure)
// then we do not continue to the next transactions.
if scope.isRequestScoped && scope.isFailure { if scope.isRequestScoped && scope.isFailure {
ctx.SkipTransactions() ctx.SkipTransactions()
} }
// finally, release and put the transaction scope back to the pool.
releaseTransactionScope(scope)
} }
// Log logs to the iris defined logger // Log logs to the iris defined logger