@@ -3,6 +3,7 @@ package handler
33import (
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
1830func 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
90140func 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