fix(M25): atomic.Pointer for Server.integrationMgr (constructor-goroutine race)
NewServer launches the SyncFileBrowserMounts goroutine (reads integrationMgr) from the constructor, BEFORE main.go's SetIntegrationManager write — so the init-only happens-before that covers the other Set* fields does NOT hold here, making it a genuine data race (handlers.go:358/360/1433 reads vs server.go:162 write). Converted the field to atomic.Pointer[integrations.Manager]; setter Stores, all 3 readers Load(). Regression test reproduces the concurrent access (clean under -race; flags on the pre-fix plain-pointer field). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -355,9 +355,9 @@ func (s *Server) deployHandler(w http.ResponseWriter, r *http.Request, name stri
|
||||
// renders those sections.
|
||||
if alreadyDeployed {
|
||||
// App-to-app integrations
|
||||
if meta.HasIntegrations() && s.integrationMgr != nil {
|
||||
if im := s.integrationMgr.Load(); meta.HasIntegrations() && im != nil {
|
||||
data["HasIntegrations"] = true
|
||||
data["Integrations"] = s.integrationMgr.ListForProvider(meta.Slug)
|
||||
data["Integrations"] = im.ListForProvider(meta.Slug)
|
||||
}
|
||||
|
||||
// Geo-restriction per-app data
|
||||
@@ -1430,8 +1430,8 @@ func (s *Server) syncFileBrowserMounts(resetDBOnChange bool) {
|
||||
}
|
||||
|
||||
// Re-apply active integrations into config.yaml (before container restart)
|
||||
if s.integrationMgr != nil {
|
||||
s.integrationMgr.ReapplyConfigForTarget("filebrowser")
|
||||
if im := s.integrationMgr.Load(); im != nil {
|
||||
im.ReapplyConfigForTarget("filebrowser")
|
||||
}
|
||||
|
||||
// Generate and write compose (includes config.yaml mount)
|
||||
|
||||
Reference in New Issue
Block a user