From 389b99f8e81e4b1053eb180d8b98d67242aa8b26 Mon Sep 17 00:00:00 2001 From: Junker der Provinz Date: Sun, 23 Aug 2026 05:53:37 +0200 Subject: [PATCH] admin: document the synchronisation SetPolicy would need beyond startup ConfigureTasksFromPolicy now really writes TaskDefinition.Config and TaskDefinition.MaxConcurrent, which the scan loop reads through detector.IsEnabled() with nothing synchronising the two. Every caller runs during admin server startup today, before the scan loop exists, so there is no live race - but the next caller has to add the locking, and the same already applies to UpdateAllConfigs replacing the whole config object. Write it down at the seam instead of leaving it to be rediscovered. Refs #10874 --- weed/admin/maintenance/maintenance_integration.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/weed/admin/maintenance/maintenance_integration.go b/weed/admin/maintenance/maintenance_integration.go index 6ccd484d5..04aa06c5d 100644 --- a/weed/admin/maintenance/maintenance_integration.go +++ b/weed/admin/maintenance/maintenance_integration.go @@ -126,6 +126,13 @@ func (s *MaintenanceIntegration) registerAllTasks() { // applies it immediately. Without this the integration kept the policy it was built with, // so a policy updated at runtime reached the queue but never the detectors that decide // which task types are scanned for. +// +// Not safe to call concurrently with a running scan. ConfigureTasksFromPolicy writes +// TaskDefinition.Config and TaskDefinition.MaxConcurrent, which ScanWithTaskDetectors reads +// through detector.IsEnabled(); nothing synchronises the two. Today every caller runs during +// admin server startup, before the scan loop exists. Anything that wires this to an HTTP +// handler has to add that synchronisation first - the same applies to +// tasks.ConfigUpdateRegistry.UpdateAllConfigs, which replaces TaskDefinition.Config outright. func (s *MaintenanceIntegration) SetPolicy(policy *MaintenancePolicy) { s.maintenancePolicy = policy s.ConfigureTasksFromPolicy()