api: fix concurrency issue when creating multiple path configs at once (#542)
This commit is contained in:
+8
-13
@@ -361,10 +361,10 @@ func (a *api) onConfigSet(ctx *gin.Context) {
|
||||
}
|
||||
|
||||
a.mutex.Lock()
|
||||
defer a.mutex.Unlock()
|
||||
|
||||
var newConf conf.Conf
|
||||
cloneStruct(a.conf, &newConf)
|
||||
a.mutex.Unlock()
|
||||
|
||||
fillStruct(&newConf, in)
|
||||
|
||||
err = newConf.CheckAndFillMissing()
|
||||
@@ -373,9 +373,7 @@ func (a *api) onConfigSet(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
a.mutex.Lock()
|
||||
a.conf = &newConf
|
||||
a.mutex.Unlock()
|
||||
|
||||
// since reloading the configuration can cause the shutdown of the API,
|
||||
// call it in a goroutine
|
||||
@@ -394,9 +392,10 @@ func (a *api) onConfigPathsAdd(ctx *gin.Context) {
|
||||
name := ctx.Param("name")
|
||||
|
||||
a.mutex.Lock()
|
||||
defer a.mutex.Unlock()
|
||||
|
||||
var newConf conf.Conf
|
||||
cloneStruct(a.conf, &newConf)
|
||||
a.mutex.Unlock()
|
||||
|
||||
if _, ok := newConf.Paths[name]; ok {
|
||||
ctx.AbortWithStatus(http.StatusBadRequest)
|
||||
@@ -413,9 +412,7 @@ func (a *api) onConfigPathsAdd(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
a.mutex.Lock()
|
||||
a.conf = &newConf
|
||||
a.mutex.Unlock()
|
||||
|
||||
// since reloading the configuration can cause the shutdown of the API,
|
||||
// call it in a goroutine
|
||||
@@ -434,9 +431,10 @@ func (a *api) onConfigPathsEdit(ctx *gin.Context) {
|
||||
name := ctx.Param("name")
|
||||
|
||||
a.mutex.Lock()
|
||||
defer a.mutex.Unlock()
|
||||
|
||||
var newConf conf.Conf
|
||||
cloneStruct(a.conf, &newConf)
|
||||
a.mutex.Unlock()
|
||||
|
||||
newConfPath, ok := newConf.Paths[name]
|
||||
if !ok {
|
||||
@@ -452,9 +450,7 @@ func (a *api) onConfigPathsEdit(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
a.mutex.Lock()
|
||||
a.conf = &newConf
|
||||
a.mutex.Unlock()
|
||||
|
||||
// since reloading the configuration can cause the shutdown of the API,
|
||||
// call it in a goroutine
|
||||
@@ -467,9 +463,10 @@ func (a *api) onConfigPathsDelete(ctx *gin.Context) {
|
||||
name := ctx.Param("name")
|
||||
|
||||
a.mutex.Lock()
|
||||
defer a.mutex.Unlock()
|
||||
|
||||
var newConf conf.Conf
|
||||
cloneStruct(a.conf, &newConf)
|
||||
a.mutex.Unlock()
|
||||
|
||||
if _, ok := newConf.Paths[name]; !ok {
|
||||
ctx.AbortWithStatus(http.StatusBadRequest)
|
||||
@@ -484,9 +481,7 @@ func (a *api) onConfigPathsDelete(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
a.mutex.Lock()
|
||||
a.conf = &newConf
|
||||
a.mutex.Unlock()
|
||||
|
||||
// since reloading the configuration can cause the shutdown of the API,
|
||||
// call it in a goroutine
|
||||
|
||||
@@ -83,7 +83,7 @@ func New(args []string) (*Core, bool) {
|
||||
err = p.createResources(true)
|
||||
if err != nil {
|
||||
p.Log(logger.Info, "ERR: %s", err)
|
||||
p.closeResources(nil)
|
||||
p.closeResources(nil, false)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ func New(args []string) (*Core, bool) {
|
||||
p.confWatcher, err = confwatcher.New(p.confPath)
|
||||
if err != nil {
|
||||
p.Log(logger.Info, "ERR: %s", err)
|
||||
p.closeResources(nil)
|
||||
p.closeResources(nil, false)
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
@@ -143,7 +143,7 @@ outer:
|
||||
break outer
|
||||
}
|
||||
|
||||
err = p.reloadConf(newConf)
|
||||
err = p.reloadConf(newConf, false)
|
||||
if err != nil {
|
||||
p.Log(logger.Info, "ERR: %s", err)
|
||||
break outer
|
||||
@@ -152,7 +152,7 @@ outer:
|
||||
case newConf := <-p.apiConfigSet:
|
||||
p.Log(logger.Info, "reloading configuration (API request)")
|
||||
|
||||
err := p.reloadConf(newConf)
|
||||
err := p.reloadConf(newConf, true)
|
||||
if err != nil {
|
||||
p.Log(logger.Info, "ERR: %s", err)
|
||||
break outer
|
||||
@@ -165,7 +165,7 @@ outer:
|
||||
|
||||
p.ctxCancel()
|
||||
|
||||
p.closeResources(nil)
|
||||
p.closeResources(nil, false)
|
||||
|
||||
if p.confWatcher != nil {
|
||||
p.confWatcher.Close()
|
||||
@@ -361,7 +361,7 @@ func (p *Core) createResources(initial bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Core) closeResources(newConf *conf.Conf) {
|
||||
func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
|
||||
closeStats := false
|
||||
if newConf == nil {
|
||||
closeStats = true
|
||||
@@ -489,7 +489,7 @@ func (p *Core) closeResources(newConf *conf.Conf) {
|
||||
if closeAPI {
|
||||
p.api.close()
|
||||
p.api = nil
|
||||
} else {
|
||||
} else if !calledByAPI { // avoid a loop
|
||||
p.api.OnConfReload(newConf)
|
||||
}
|
||||
}
|
||||
@@ -539,8 +539,8 @@ func (p *Core) closeResources(newConf *conf.Conf) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Core) reloadConf(newConf *conf.Conf) error {
|
||||
p.closeResources(newConf)
|
||||
func (p *Core) reloadConf(newConf *conf.Conf, calledByAPI bool) error {
|
||||
p.closeResources(newConf, calledByAPI)
|
||||
|
||||
p.conf = newConf
|
||||
return p.createResources(false)
|
||||
|
||||
Reference in New Issue
Block a user