Implement in-application mutex to reduce DB_LOCKED errors
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
golock "github.com/viney-shih/go-lock"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/ginext"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/rext"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/syncext"
|
||||
@@ -38,14 +39,16 @@ type Application struct {
|
||||
Port string
|
||||
IsRunning *syncext.AtomicBool
|
||||
RequestLogQueue chan models.RequestLog
|
||||
MainDatabaseLock golock.RWMutex
|
||||
}
|
||||
|
||||
func NewApp(db *DBPool) *Application {
|
||||
return &Application{
|
||||
Database: db,
|
||||
stopChan: make(chan bool),
|
||||
IsRunning: syncext.NewAtomicBool(false),
|
||||
RequestLogQueue: make(chan models.RequestLog, 1024),
|
||||
Database: db,
|
||||
stopChan: make(chan bool),
|
||||
IsRunning: syncext.NewAtomicBool(false),
|
||||
RequestLogQueue: make(chan models.RequestLog, 1024),
|
||||
MainDatabaseLock: golock.NewCASMutex(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -23,7 +23,7 @@ type RequestOptions struct {
|
||||
IgnoreWrongContentType bool
|
||||
}
|
||||
|
||||
func (app *Application) DoRequest(gectx *ginext.AppContext, g *gin.Context, fn func(ctx *AppContext, finishSuccess func(r ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse {
|
||||
func (app *Application) DoRequest(gectx *ginext.AppContext, g *gin.Context, lockmode models.TransactionLockMode, fn func(ctx *AppContext, finishSuccess func(r ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse {
|
||||
|
||||
maxRetry := scn.Conf.RequestMaxRetry
|
||||
retrySleep := scn.Conf.RequestRetrySleep
|
||||
@@ -40,6 +40,29 @@ func (app *Application) DoRequest(gectx *ginext.AppContext, g *gin.Context, fn f
|
||||
|
||||
wrap, stackTrace, panicObj := callPanicSafe(func(ctx *AppContext, finishSuccess func(r ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse {
|
||||
|
||||
dl, ok := ctx.Deadline()
|
||||
if !ok {
|
||||
dl = time.Now().Add(time.Second * 5)
|
||||
}
|
||||
|
||||
if lockmode == models.TLockRead {
|
||||
|
||||
islock := app.MainDatabaseLock.RTryLockWithTimeout(dl.Sub(time.Now()))
|
||||
if !islock {
|
||||
return ginresp.APIError(g, 500, apierr.INTERNAL_EXCEPTION, "Failed to lock {MainDatabaseLock} [ro]", nil)
|
||||
}
|
||||
defer app.MainDatabaseLock.RUnlock()
|
||||
|
||||
} else if lockmode == models.TLockReadWrite {
|
||||
|
||||
islock := app.MainDatabaseLock.TryLockWithTimeout(dl.Sub(time.Now()))
|
||||
if !islock {
|
||||
return ginresp.APIError(g, 500, apierr.INTERNAL_EXCEPTION, "Failed to lock {MainDatabaseLock} [rw]", nil)
|
||||
}
|
||||
defer app.MainDatabaseLock.Unlock()
|
||||
|
||||
}
|
||||
|
||||
authheader := g.GetHeader("Authorization")
|
||||
|
||||
perm, err := app.getPermissions(actx, authheader)
|
||||
|
Reference in New Issue
Block a user