refactor(plugin): rename detection_interval_seconds → detection_interval_minutes (#9366)

Minutes is the natural granularity for detection cadence — every
production handler already set the seconds field to a 60-multiple
(17*60, 30*60, 3600, 24*60*60). Switching to minutes drops the *60
arithmetic and matches the unit conventions used elsewhere in the
plugin worker forms.

- Proto: AdminRuntimeDefaults + AdminRuntimeConfig.detection_interval_*
  field renamed.
- Helpers: durationFromMinutes / minutesFromDuration alongside the
  existing seconds variants in plugin_scheduler.go.
- Handlers: vacuum, ec_balance, balance, erasure_coding, iceberg,
  admin_script, s3_lifecycle now declare DetectionIntervalMinutes.
- Admin: scheduler_status + types + UI templ + plugin_api.go pass
  through the new field; UI label and table cells switch to "min".
This commit is contained in:
Chris Lu
2026-05-08 10:33:02 -07:00
committed by GitHub
parent 7f254e158e
commit 5d43f84df7
23 changed files with 64 additions and 50 deletions
+1 -1
View File
@@ -1036,7 +1036,7 @@ func (r *Plugin) ensureJobTypeConfigFromDescriptor(jobType string, descriptor *p
defaults := descriptor.AdminRuntimeDefaults
adminRuntime = &plugin_pb.AdminRuntimeConfig{
Enabled: defaults.Enabled,
DetectionIntervalSeconds: defaults.DetectionIntervalSeconds,
DetectionIntervalMinutes: defaults.DetectionIntervalMinutes,
DetectionTimeoutSeconds: defaults.DetectionTimeoutSeconds,
MaxJobsPerDetection: defaults.MaxJobsPerDetection,
GlobalExecutionConcurrency: defaults.GlobalExecutionConcurrency,
@@ -30,7 +30,7 @@ func TestEnsureJobTypeConfigFromDescriptorBootstrapsDefaults(t *testing.T) {
},
AdminRuntimeDefaults: &plugin_pb.AdminRuntimeDefaults{
Enabled: true,
DetectionIntervalSeconds: 60,
DetectionIntervalMinutes: 60,
DetectionTimeoutSeconds: 20,
MaxJobsPerDetection: 30,
GlobalExecutionConcurrency: 4,
+19 -5
View File
@@ -466,7 +466,7 @@ func (r *Plugin) loadSchedulerPolicy(jobType string) (schedulerPolicy, bool, err
}
policy := schedulerPolicy{
DetectionInterval: durationFromSeconds(adminRuntime.DetectionIntervalSeconds, defaultScheduledDetectionInterval),
DetectionInterval: durationFromMinutes(adminRuntime.DetectionIntervalMinutes, defaultScheduledDetectionInterval),
DetectionTimeout: durationFromSeconds(adminRuntime.DetectionTimeoutSeconds, defaultScheduledDetectionTimeout),
ExecutionTimeout: durationFromSeconds(adminRuntime.ExecutionTimeoutSeconds, defaultScheduledExecutionTimeout),
JobTypeMaxRuntime: durationFromSeconds(adminRuntime.JobTypeMaxRuntimeSeconds, defaultScheduledJobTypeMaxRuntime),
@@ -548,7 +548,7 @@ func (r *Plugin) ListSchedulerStates() ([]SchedulerJobTypeState, error) {
} else {
state.Enabled = enabled
if enabled {
state.DetectionIntervalSeconds = secondsFromDuration(policy.DetectionInterval)
state.DetectionIntervalMinutes = minutesFromDuration(policy.DetectionInterval)
state.DetectionTimeoutSeconds = secondsFromDuration(policy.DetectionTimeout)
state.ExecutionTimeoutSeconds = secondsFromDuration(policy.ExecutionTimeout)
state.JobTypeMaxRuntimeSeconds = secondsFromDuration(policy.JobTypeMaxRuntime)
@@ -613,8 +613,8 @@ func deriveSchedulerAdminRuntime(
// default instead of the handler's declared baseline.
if descriptor != nil && descriptor.AdminRuntimeDefaults != nil {
defaults := descriptor.AdminRuntimeDefaults
if adminConfig.DetectionIntervalSeconds <= 0 {
adminConfig.DetectionIntervalSeconds = defaults.DetectionIntervalSeconds
if adminConfig.DetectionIntervalMinutes <= 0 {
adminConfig.DetectionIntervalMinutes = defaults.DetectionIntervalMinutes
}
if adminConfig.DetectionTimeoutSeconds <= 0 {
adminConfig.DetectionTimeoutSeconds = defaults.DetectionTimeoutSeconds
@@ -648,7 +648,7 @@ func deriveSchedulerAdminRuntime(
defaults := descriptor.AdminRuntimeDefaults
return &plugin_pb.AdminRuntimeConfig{
Enabled: defaults.Enabled,
DetectionIntervalSeconds: defaults.DetectionIntervalSeconds,
DetectionIntervalMinutes: defaults.DetectionIntervalMinutes,
DetectionTimeoutSeconds: defaults.DetectionTimeoutSeconds,
MaxJobsPerDetection: defaults.MaxJobsPerDetection,
GlobalExecutionConcurrency: defaults.GlobalExecutionConcurrency,
@@ -1366,6 +1366,13 @@ func durationFromSeconds(seconds int32, defaultValue time.Duration) time.Duratio
return time.Duration(seconds) * time.Second
}
func durationFromMinutes(minutes int32, defaultValue time.Duration) time.Duration {
if minutes <= 0 {
return defaultValue
}
return time.Duration(minutes) * time.Minute
}
func secondsFromDuration(duration time.Duration) int32 {
if duration <= 0 {
return 0
@@ -1373,6 +1380,13 @@ func secondsFromDuration(duration time.Duration) int32 {
return int32(duration / time.Second)
}
func minutesFromDuration(duration time.Duration) int32 {
if duration <= 0 {
return 0
}
return int32(duration / time.Minute)
}
func waitForShutdownOrTimerWithContext(shutdown <-chan struct{}, ctx context.Context, duration time.Duration) bool {
if duration <= 0 {
return true
+6 -6
View File
@@ -23,7 +23,7 @@ func TestLoadSchedulerPolicyUsesAdminConfig(t *testing.T) {
JobType: "vacuum",
AdminRuntime: &plugin_pb.AdminRuntimeConfig{
Enabled: true,
DetectionIntervalSeconds: 30,
DetectionIntervalMinutes: 30,
DetectionTimeoutSeconds: 20,
MaxJobsPerDetection: 123,
GlobalExecutionConcurrency: 5,
@@ -74,7 +74,7 @@ func TestLoadSchedulerPolicyUsesDescriptorDefaultsWhenConfigMissing(t *testing.T
JobType: "ec",
AdminRuntimeDefaults: &plugin_pb.AdminRuntimeDefaults{
Enabled: true,
DetectionIntervalSeconds: 60,
DetectionIntervalMinutes: 60,
DetectionTimeoutSeconds: 25,
MaxJobsPerDetection: 30,
GlobalExecutionConcurrency: 4,
@@ -397,7 +397,7 @@ func TestListSchedulerStatesIncludesPolicyAndState(t *testing.T) {
JobType: jobType,
AdminRuntime: &plugin_pb.AdminRuntimeConfig{
Enabled: true,
DetectionIntervalSeconds: 45,
DetectionIntervalMinutes: 45,
DetectionTimeoutSeconds: 30,
MaxJobsPerDetection: 80,
GlobalExecutionConcurrency: 3,
@@ -448,8 +448,8 @@ func TestListSchedulerStatesIncludesPolicyAndState(t *testing.T) {
if state.NextDetectionAt.Unix() != nextDetectionAt.Unix() {
t.Fatalf("unexpected next detection time: got=%v want=%v", state.NextDetectionAt, nextDetectionAt)
}
if state.DetectionIntervalSeconds != 45 {
t.Fatalf("unexpected detection interval: got=%d", state.DetectionIntervalSeconds)
if state.DetectionIntervalMinutes != 45 {
t.Fatalf("unexpected detection interval: got=%d", state.DetectionIntervalMinutes)
}
if state.DetectionTimeoutSeconds != 30 {
t.Fatalf("unexpected detection timeout: got=%d", state.DetectionTimeoutSeconds)
@@ -657,7 +657,7 @@ func TestRunLaneSchedulerIterationLockBehavior(t *testing.T) {
JobType: tt.jobType,
AdminRuntime: &plugin_pb.AdminRuntimeConfig{
Enabled: true,
DetectionIntervalSeconds: 1,
DetectionIntervalMinutes: 1,
},
})
if err != nil {
+3 -3
View File
@@ -47,7 +47,7 @@ type SchedulerJobTypeStatus struct {
Enabled bool `json:"enabled"`
DetectionInFlight bool `json:"detection_in_flight"`
NextDetectionAt *time.Time `json:"next_detection_at,omitempty"`
DetectionIntervalSeconds int32 `json:"detection_interval_seconds,omitempty"`
DetectionIntervalMinutes int32 `json:"detection_interval_minutes,omitempty"`
LastDetectedAt *time.Time `json:"last_detected_at,omitempty"`
LastDetectedCount int `json:"last_detected_count,omitempty"`
LastDetectionError string `json:"last_detection_error,omitempty"`
@@ -347,7 +347,7 @@ func (r *Plugin) GetLaneSchedulerStatus(lane SchedulerLane) SchedulerStatus {
Enabled: state.Enabled,
DetectionInFlight: state.DetectionInFlight,
NextDetectionAt: state.NextDetectionAt,
DetectionIntervalSeconds: state.DetectionIntervalSeconds,
DetectionIntervalMinutes: state.DetectionIntervalMinutes,
}
if !info.lastDetectedAt.IsZero() {
jobStatus.LastDetectedAt = timeToPtr(info.lastDetectedAt)
@@ -430,7 +430,7 @@ func (r *Plugin) GetSchedulerStatus() SchedulerStatus {
Enabled: state.Enabled,
DetectionInFlight: state.DetectionInFlight,
NextDetectionAt: state.NextDetectionAt,
DetectionIntervalSeconds: state.DetectionIntervalSeconds,
DetectionIntervalMinutes: state.DetectionIntervalMinutes,
}
if !info.lastDetectedAt.IsZero() {
jobStatus.LastDetectedAt = timeToPtr(info.lastDetectedAt)
+1 -1
View File
@@ -90,7 +90,7 @@ func TestGetLaneSchedulerStatusShowsActiveConcurrentLaneWork(t *testing.T) {
JobType: jobType,
AdminRuntime: &plugin_pb.AdminRuntimeConfig{
Enabled: true,
DetectionIntervalSeconds: 30,
DetectionIntervalMinutes: 30,
DetectionTimeoutSeconds: 15,
},
})
+1 -1
View File
@@ -88,7 +88,7 @@ type SchedulerJobTypeState struct {
PolicyError string `json:"policy_error,omitempty"`
DetectionInFlight bool `json:"detection_in_flight"`
NextDetectionAt *time.Time `json:"next_detection_at,omitempty"`
DetectionIntervalSeconds int32 `json:"detection_interval_seconds,omitempty"`
DetectionIntervalMinutes int32 `json:"detection_interval_minutes,omitempty"`
DetectionTimeoutSeconds int32 `json:"detection_timeout_seconds,omitempty"`
ExecutionTimeoutSeconds int32 `json:"execution_timeout_seconds,omitempty"`
JobTypeMaxRuntimeSeconds int32 `json:"job_type_max_runtime_seconds,omitempty"`