Skip to content

Commit a8484b6

Browse files
committed
Add SPO_PROCESS_MAX_LIFETIME option for k8s 1.20 bug work-around
1 parent 7ae1941 commit a8484b6

2 files changed

Lines changed: 21 additions & 1 deletion

File tree

src/main/kotlin/eu/openanalytics/shinyproxyoperator/Operator.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class Operator(client: NamespacedKubernetesClient? = null,
7272
val probeFailureThreshold: Int
7373
val probeTimeout: Int
7474
val startupProbeInitialDelay: Int
75+
val processMaxLifetime: Long
7576

7677
private val podSetCustomResourceDefinitionContext = CustomResourceDefinitionContext.Builder()
7778
.withVersion("v1alpha1")
@@ -112,6 +113,19 @@ class Operator(client: NamespacedKubernetesClient? = null,
112113
this.probeFailureThreshold = readConfigValue(probeFailureThreshold, 0, "SPO_PROBE_FAILURE_THRESHOLD", String::toInt)
113114
this.probeTimeout = readConfigValue(probeTimeout, 1, "SPO_PROBE_TIMEOUT", String::toInt)
114115
this.startupProbeInitialDelay = readConfigValue(startupProbeInitialDelay, 60, "SPO_STARTUP_PROBE_INITIAL_DELAY", String::toInt)
116+
this.processMaxLifetime = readConfigValue(null, -1, "SPO_PROCESS_MAX_LIFETIME", String::toLong)
117+
if (this.processMaxLifetime != -1L) {
118+
Timer().schedule(this.processMaxLifetime * 60 * 1000) {
119+
logger.warn { "Max lifetime of process reached, preparing shutdown" }
120+
sendChannel.close();
121+
while (!channel.isClosedForReceive && !channel.isEmpty && !shinyProxyController.idle) {
122+
logger.warn { "Still processing events in queue, delaying shutdown" }
123+
Thread.sleep(250)
124+
}
125+
logger.warn { "Queue is empty, exiting process" }
126+
exitProcess(1);
127+
}
128+
}
115129

116130
val rootLogger = LoggerFactory.getILoggerFactory().getLogger(Logger.ROOT_LOGGER_NAME) as Logger
117131
rootLogger.level = readConfigValue(logLevel, Level.DEBUG, "SPO_LOG_LEVEL", { Level.toLevel(it) })

src/main/kotlin/eu/openanalytics/shinyproxyoperator/controller/ShinyProxyController.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,15 @@ class ShinyProxyController(private val channel: Channel<ShinyProxyEvent>,
6262

6363
private val scope = CoroutineScope(Dispatchers.Default)
6464

65+
@Volatile
66+
public var idle: Boolean = true
67+
private set
68+
6569
suspend fun run() {
6670
scope.launch { scheduleAdditionalEvents() }
6771
while (true) {
6872
try {
73+
idle = true
6974
receiveAndHandleEvent()
7075
} catch (cancellationException: CancellationException) {
7176
logger.warn { "Controller cancelled -> stopping" }
@@ -114,6 +119,7 @@ class ShinyProxyController(private val channel: Channel<ShinyProxyEvent>,
114119
}
115120

116121
val event = channel.receive()
122+
idle = false
117123
for (i in 1..5) {
118124
try {
119125
tryReceiveAndHandleEvent(event)
@@ -327,7 +333,7 @@ class ShinyProxyController(private val channel: Channel<ShinyProxyEvent>,
327333
it.status.instances.remove(shinyProxyInstance)
328334
}
329335

330-
// Important: remove ingress before removing the ReplicaSet. This ensures that the rotues are correclty updated in the Ingress
336+
// Important: remove ingress before removing the ReplicaSet. This ensures that the routes are correctly updated in the Ingress
331337
// and users aren't routed to non-existing pods
332338
logger.info { "${shinyProxy.logPrefix(shinyProxyInstance)} DeleteSingleShinyProxyInstance [Step 2/3]: Update Ingress" }
333339
ingressController.onRemoveInstance(shinyProxy, shinyProxyInstance)

0 commit comments

Comments
 (0)