Skip to content

Commit 16885fc

Browse files
committed
Add missing timer handling
1 parent 785e7bb commit 16885fc

1 file changed

Lines changed: 80 additions & 2 deletions

File tree

internal/pkg/handler/pause_deployment.go

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package handler
33
import (
44
"context"
55
"fmt"
6+
"sync"
67
"time"
78

89
"github.com/sirupsen/logrus"
@@ -14,6 +15,17 @@ import (
1415
"k8s.io/apimachinery/pkg/runtime"
1516
)
1617

18+
// Keeps track of currently active timers for paused deployments
19+
var (
20+
activeTimers = make(map[string]*time.Timer)
21+
timerLock = sync.Mutex{}
22+
)
23+
24+
// Returns unique key for the activeTimers map
25+
func getTimerKey(namespace, deploymentName string) string {
26+
return fmt.Sprintf("%s/%s", namespace, deploymentName)
27+
}
28+
1729
// IsPaused checks if a deployment is currently paused
1830
func IsPaused(deployment *app.Deployment) bool {
1931
return deployment.Spec.Paused
@@ -78,19 +90,75 @@ func PauseDeployment(deployment *app.Deployment, clients kube.Clients, deploymen
7890
deployment.Annotations = make(map[string]string)
7991
}
8092
deployment.Annotations[options.PauseDeploymentTimeAnnotation] = time.Now().Format(time.RFC3339)
93+
deployment.Annotations[options.PauseDeploymentAnnotation] = pauseIntervalValue
8194

8295
CreateResumeTimer(deployment, clients, deploymentName, namespace, pauseDuration)
96+
} else if IsPausedByReloader(deployment) {
97+
logrus.Debugf("Deployment '%s' in namespace '%s' is already paused by reloader", deploymentName, namespace)
98+
99+
// Check if a timer already exists for this deployment
100+
timerKey := getTimerKey(namespace, deploymentName)
101+
timerLock.Lock()
102+
_, timerExists := activeTimers[timerKey]
103+
timerLock.Unlock()
104+
105+
if !timerExists {
106+
logrus.Warnf("Timer does not exist for already paused deployment '%s' in namespace '%s', creating new one",
107+
deploymentName, namespace)
108+
HandleMissingTimer(deployment, pauseDuration, clients, deploymentName, namespace)
109+
}
110+
83111
} else {
84-
logrus.Infof("Deployment '%s' in namespace '%s' is already paused", deploymentName, namespace)
112+
logrus.Infof("Deployment '%s' in namespace '%s' already paused", deploymentName, namespace)
85113
}
86114
return nil
87115
}
88116

117+
func HandleMissingTimer(deployment *app.Deployment, pauseDuration time.Duration, clients kube.Clients, deploymentName, namespace string) {
118+
pauseStartTime, err := GetPauseStartTime(deployment)
119+
if err != nil {
120+
logrus.Errorf("Error parsing pause start time for deployment '%s' in namespace '%s': %v. Resuming deployment immediately",
121+
deploymentName, namespace, err)
122+
ResumeDeployment(deploymentName, namespace, clients)
123+
} else if pauseStartTime != nil {
124+
elapsedTime := time.Since(*pauseStartTime)
125+
remainingTime := pauseDuration - elapsedTime
126+
127+
if remainingTime <= 0 {
128+
logrus.Infof("Pause period for deployment '%s' in namespace '%s' has expired. Resuming immediately",
129+
deploymentName, namespace)
130+
ResumeDeployment(deploymentName, namespace, clients)
131+
} else {
132+
logrus.Infof("Creating missing timer for already paused deployment '%s' in namespace '%s' with remaining time %s",
133+
deploymentName, namespace, remainingTime)
134+
CreateResumeTimer(deployment, clients, deploymentName, namespace, remainingTime)
135+
}
136+
}
137+
}
138+
89139
// CreateResumeTimer creates a timer to resume the deployment after the specified duration
90140
func CreateResumeTimer(deployment *app.Deployment, clients kube.Clients, deploymentName, namespace string, pauseDuration time.Duration) {
91-
time.AfterFunc(pauseDuration, func() {
141+
timerKey := getTimerKey(namespace, deploymentName)
142+
143+
// Check if there's an existing timer for this deployment
144+
timerLock.Lock()
145+
if _, exists := activeTimers[timerKey]; exists {
146+
logrus.Debugf("Timer already exists for deployment '%s' in namespace '%s', Skipping creation",
147+
deploymentName, namespace)
148+
return
149+
}
150+
151+
// Create and store the new timer
152+
timer := time.AfterFunc(pauseDuration, func() {
92153
ResumeDeployment(deploymentName, namespace, clients)
93154
})
155+
156+
// Add the new timer to the map
157+
activeTimers[timerKey] = timer
158+
timerLock.Unlock()
159+
160+
logrus.Debugf("Created pause timer for deployment '%s' in namespace '%s' with duration %s",
161+
deploymentName, namespace, pauseDuration)
94162
}
95163

96164
// ResumeDeployment resumes a deployment that has been paused by reloader
@@ -106,6 +174,16 @@ func ResumeDeployment(deploymentName, namespace string, clients kube.Clients) {
106174
return
107175
}
108176

177+
// Remove the timer itself
178+
timerKey := getTimerKey(namespace, deploymentName)
179+
timerLock.Lock()
180+
if timer, exists := activeTimers[timerKey]; exists {
181+
timer.Stop()
182+
delete(activeTimers, timerKey)
183+
logrus.Debugf("Removed pause timer for deployment '%s' in namespace '%s'", deploymentName, namespace)
184+
}
185+
timerLock.Unlock()
186+
109187
deployment.Spec.Paused = false
110188
delete(deployment.Annotations, options.PauseDeploymentTimeAnnotation)
111189

0 commit comments

Comments
 (0)