Browse Source

api: fix concurrency issue when creating multiple path configs at once (#542)

pull/591/head
aler9 5 years ago
parent
commit
ddcd0c34cf
  1. 21
      internal/core/api.go
  2. 18
      internal/core/core.go

21
internal/core/api.go

@ -361,10 +361,10 @@ func (a *api) onConfigSet(ctx *gin.Context) {
} }
a.mutex.Lock() a.mutex.Lock()
defer a.mutex.Unlock()
var newConf conf.Conf var newConf conf.Conf
cloneStruct(a.conf, &newConf) cloneStruct(a.conf, &newConf)
a.mutex.Unlock()
fillStruct(&newConf, in) fillStruct(&newConf, in)
err = newConf.CheckAndFillMissing() err = newConf.CheckAndFillMissing()
@ -373,9 +373,7 @@ func (a *api) onConfigSet(ctx *gin.Context) {
return return
} }
a.mutex.Lock()
a.conf = &newConf a.conf = &newConf
a.mutex.Unlock()
// since reloading the configuration can cause the shutdown of the API, // since reloading the configuration can cause the shutdown of the API,
// call it in a goroutine // call it in a goroutine
@ -394,9 +392,10 @@ func (a *api) onConfigPathsAdd(ctx *gin.Context) {
name := ctx.Param("name") name := ctx.Param("name")
a.mutex.Lock() a.mutex.Lock()
defer a.mutex.Unlock()
var newConf conf.Conf var newConf conf.Conf
cloneStruct(a.conf, &newConf) cloneStruct(a.conf, &newConf)
a.mutex.Unlock()
if _, ok := newConf.Paths[name]; ok { if _, ok := newConf.Paths[name]; ok {
ctx.AbortWithStatus(http.StatusBadRequest) ctx.AbortWithStatus(http.StatusBadRequest)
@ -413,9 +412,7 @@ func (a *api) onConfigPathsAdd(ctx *gin.Context) {
return return
} }
a.mutex.Lock()
a.conf = &newConf a.conf = &newConf
a.mutex.Unlock()
// since reloading the configuration can cause the shutdown of the API, // since reloading the configuration can cause the shutdown of the API,
// call it in a goroutine // call it in a goroutine
@ -434,9 +431,10 @@ func (a *api) onConfigPathsEdit(ctx *gin.Context) {
name := ctx.Param("name") name := ctx.Param("name")
a.mutex.Lock() a.mutex.Lock()
defer a.mutex.Unlock()
var newConf conf.Conf var newConf conf.Conf
cloneStruct(a.conf, &newConf) cloneStruct(a.conf, &newConf)
a.mutex.Unlock()
newConfPath, ok := newConf.Paths[name] newConfPath, ok := newConf.Paths[name]
if !ok { if !ok {
@ -452,9 +450,7 @@ func (a *api) onConfigPathsEdit(ctx *gin.Context) {
return return
} }
a.mutex.Lock()
a.conf = &newConf a.conf = &newConf
a.mutex.Unlock()
// since reloading the configuration can cause the shutdown of the API, // since reloading the configuration can cause the shutdown of the API,
// call it in a goroutine // call it in a goroutine
@ -467,9 +463,10 @@ func (a *api) onConfigPathsDelete(ctx *gin.Context) {
name := ctx.Param("name") name := ctx.Param("name")
a.mutex.Lock() a.mutex.Lock()
defer a.mutex.Unlock()
var newConf conf.Conf var newConf conf.Conf
cloneStruct(a.conf, &newConf) cloneStruct(a.conf, &newConf)
a.mutex.Unlock()
if _, ok := newConf.Paths[name]; !ok { if _, ok := newConf.Paths[name]; !ok {
ctx.AbortWithStatus(http.StatusBadRequest) ctx.AbortWithStatus(http.StatusBadRequest)
@ -484,9 +481,7 @@ func (a *api) onConfigPathsDelete(ctx *gin.Context) {
return return
} }
a.mutex.Lock()
a.conf = &newConf a.conf = &newConf
a.mutex.Unlock()
// since reloading the configuration can cause the shutdown of the API, // since reloading the configuration can cause the shutdown of the API,
// call it in a goroutine // call it in a goroutine

18
internal/core/core.go

@ -83,7 +83,7 @@ func New(args []string) (*Core, bool) {
err = p.createResources(true) err = p.createResources(true)
if err != nil { if err != nil {
p.Log(logger.Info, "ERR: %s", err) p.Log(logger.Info, "ERR: %s", err)
p.closeResources(nil) p.closeResources(nil, false)
return nil, false return nil, false
} }
@ -91,7 +91,7 @@ func New(args []string) (*Core, bool) {
p.confWatcher, err = confwatcher.New(p.confPath) p.confWatcher, err = confwatcher.New(p.confPath)
if err != nil { if err != nil {
p.Log(logger.Info, "ERR: %s", err) p.Log(logger.Info, "ERR: %s", err)
p.closeResources(nil) p.closeResources(nil, false)
return nil, false return nil, false
} }
} }
@ -143,7 +143,7 @@ outer:
break outer break outer
} }
err = p.reloadConf(newConf) err = p.reloadConf(newConf, false)
if err != nil { if err != nil {
p.Log(logger.Info, "ERR: %s", err) p.Log(logger.Info, "ERR: %s", err)
break outer break outer
@ -152,7 +152,7 @@ outer:
case newConf := <-p.apiConfigSet: case newConf := <-p.apiConfigSet:
p.Log(logger.Info, "reloading configuration (API request)") p.Log(logger.Info, "reloading configuration (API request)")
err := p.reloadConf(newConf) err := p.reloadConf(newConf, true)
if err != nil { if err != nil {
p.Log(logger.Info, "ERR: %s", err) p.Log(logger.Info, "ERR: %s", err)
break outer break outer
@ -165,7 +165,7 @@ outer:
p.ctxCancel() p.ctxCancel()
p.closeResources(nil) p.closeResources(nil, false)
if p.confWatcher != nil { if p.confWatcher != nil {
p.confWatcher.Close() p.confWatcher.Close()
@ -361,7 +361,7 @@ func (p *Core) createResources(initial bool) error {
return nil return nil
} }
func (p *Core) closeResources(newConf *conf.Conf) { func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
closeStats := false closeStats := false
if newConf == nil { if newConf == nil {
closeStats = true closeStats = true
@ -489,7 +489,7 @@ func (p *Core) closeResources(newConf *conf.Conf) {
if closeAPI { if closeAPI {
p.api.close() p.api.close()
p.api = nil p.api = nil
} else { } else if !calledByAPI { // avoid a loop
p.api.OnConfReload(newConf) p.api.OnConfReload(newConf)
} }
} }
@ -539,8 +539,8 @@ func (p *Core) closeResources(newConf *conf.Conf) {
} }
} }
func (p *Core) reloadConf(newConf *conf.Conf) error { func (p *Core) reloadConf(newConf *conf.Conf, calledByAPI bool) error {
p.closeResources(newConf) p.closeResources(newConf, calledByAPI)
p.conf = newConf p.conf = newConf
return p.createResources(false) return p.createResources(false)

Loading…
Cancel
Save