@@ -16,8 +16,12 @@ import (
16
16
"sigs.k8s.io/controller-runtime/pkg/log"
17
17
)
18
18
19
+ // If the cpu usage of the session is less than this then the session is considered idle
19
20
var cpuUsageIdlenessThreshold resource.Quantity = * resource .NewMilliQuantity (300 , resource .DecimalSI )
20
21
22
+ // If the last request performed in the user session is older than this the session is considered idle
23
+ const lastRequestAgeThreshold time.Duration = time .Minute * 30
24
+
21
25
// countainerCounts provides from the total and completed/fully running containers in a pod.
22
26
// The output is a tuple with the init container counts followed by the regular container counts.
23
27
func containerCounts (pod * v1.Pod ) (amaltheadevv1alpha1.ContainerCounts , amaltheadevv1alpha1.ContainerCounts ) {
@@ -82,7 +86,7 @@ func metrics(ctx context.Context, clnt metricsv1beta1.PodMetricsesGetter, cr *am
82
86
return nil , fmt .Errorf ("could not find the metrics for the session container %s" , amaltheadevv1alpha1 .SessionContainerName )
83
87
}
84
88
85
- func lastRequestTime (cr * amaltheadevv1alpha1.AmaltheaSession ) (time.Time , error ) {
89
+ func getLastRequestTime (cr * amaltheadevv1alpha1.AmaltheaSession ) (time.Time , error ) {
86
90
url := fmt .Sprintf ("http://%s:%d/request_stats" , cr .Service ().Name , amaltheadevv1alpha1 .AuthProxyMetaPort )
87
91
88
92
resp , err := http .Get (url )
@@ -107,6 +111,14 @@ func lastRequestTime(cr *amaltheadevv1alpha1.AmaltheaSession) (time.Time, error)
107
111
return req_stats .LastRequestTime , nil
108
112
}
109
113
114
+ type IdleDecision int
115
+
116
+ // The values are setup in a way so that max(x, y, z) where x, y, z are
117
+ // one of the values below will give the final decision.
118
+ const Unknown IdleDecision = 0
119
+ const Idle IdleDecision = 1
120
+ const NotIdle IdleDecision = 2
121
+
110
122
func getIdleState (
111
123
ctx context.Context ,
112
124
r * AmaltheaSessionReconciler ,
@@ -117,41 +129,49 @@ func getIdleState(
117
129
return metav1.Time {}, false
118
130
}
119
131
idleSince := cr .Status .IdleSince
120
- idle := false
121
132
133
+ cpuIdle := Unknown
134
+ var cpuUsage * resource.Quantity
122
135
metrics , err := metrics (ctx , r .MetricsClient , cr )
123
136
if err != nil {
124
- log .Info ("Metrics returned error" , "error" , err )
125
- return metav1.Time {}, false
137
+ log .Info ("Metrics returned error when checking idleness" , "error" , err )
138
+ } else {
139
+ cpuUsage = metrics .Cpu ()
126
140
}
127
-
128
- cpuUsage := metrics .Cpu ()
129
- if cpuUsage != nil && cpuUsage .Cmp (cpuUsageIdlenessThreshold ) == - 1 {
130
- if cr .Status .IdleSince .IsZero () {
131
- log .Info (
132
- "the session was found to be idle" ,
133
- "cpu usage milicores" ,
134
- cpuUsage .MilliValue (),
135
- "idle threshold milicores" ,
136
- cpuUsageIdlenessThreshold .MilliValue (),
137
- )
141
+ if cpuUsage != nil {
142
+ if cpuUsage .Cmp (cpuUsageIdlenessThreshold ) == - 1 {
143
+ cpuIdle = Idle
144
+ } else {
145
+ cpuIdle = NotIdle
138
146
}
139
- idle = true
140
- // check last request time before setting session to idle
141
- rt , err := lastRequestTime (cr )
142
- if err == nil && (idleSince .IsZero () || idleSince .Time .Before (rt )) {
143
- log .Info ("the last request to the session happened after the session became idle, skipping marking as idle" )
144
- idleSince = metav1 .NewTime (rt )
145
- } else if err != nil {
146
- // note, if there was an error getting the time, we continue as normal
147
- log .Info ("Couldn't get last request time from proxy" , "err" , err )
147
+ }
148
+
149
+ requestIdle := Unknown
150
+ lastRequesTime , err := getLastRequestTime (cr )
151
+ if err != nil {
152
+ log .Info ("Request time check returned an error when checking idleness" , "error" , err )
153
+ } else {
154
+ if time .Since (lastRequesTime ) >= lastRequestAgeThreshold {
155
+ requestIdle = Idle
156
+ } else {
157
+ requestIdle = NotIdle
148
158
}
149
159
}
150
160
161
+ idle := false
162
+ // If the decision is Unknown or there is at least 1 NotIdle then we keep the final status not idle.
163
+ // If there is 2 Idle or an Unknown and an Idle then the status is Idle.
164
+ decision := max (cpuIdle , requestIdle )
165
+ if decision == Idle {
166
+ idle = true
167
+ }
151
168
if idle && idleSince .IsZero () {
152
169
idleSince = metav1 .NewTime (time .Now ())
153
170
} else if ! idle && ! idleSince .IsZero () {
154
171
idleSince = metav1.Time {}
155
172
}
173
+
174
+ log .Info ("session idle check" , "idle" , idle , "session" , cr .Name , "cpuUsage" , cpuUsage , "cpuUsageThreshold" , cpuUsageIdlenessThreshold , "lastRequestTime" , lastRequesTime , "lastRequestAgeThreshold" , lastRequestAgeThreshold )
175
+
156
176
return idleSince , idle
157
177
}
0 commit comments