Skip to content

Commit 04ff88e

Browse files
committed
Fix #24210: releases proxies which reached max-lifetime
1 parent 4efe3c1 commit 04ff88e

2 files changed

Lines changed: 108 additions & 0 deletions

File tree

src/main/java/eu/openanalytics/containerproxy/model/spec/ProxySpec.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ public class ProxySpec {
4343
private List<String> kubernetesAdditionalManifests = new ArrayList<>();
4444
private List<String> kubernetesAdditionalPersistentManifests = new ArrayList<>();
4545

46+
private Long maxLifeTime;
47+
4648
public ProxySpec() {
4749
settings = new HashMap<>();
4850
}
@@ -152,12 +154,21 @@ public List<String> getKubernetesAdditionalPersistentManifests() {
152154
return kubernetesAdditionalPersistentManifests;
153155
}
154156

157+
public Long getMaxLifeTime() {
158+
return maxLifeTime;
159+
}
160+
161+
public void setMaxLifeTime(Long maxLifeTime) {
162+
this.maxLifeTime = maxLifeTime;
163+
}
164+
155165

156166
public void copy(ProxySpec target) {
157167
target.setId(id);
158168
target.setDisplayName(displayName);
159169
target.setDescription(description);
160170
target.setLogoURL(logoURL);
171+
target.setMaxLifeTime(maxLifeTime);
161172

162173
if (accessControl != null) {
163174
if (target.getAccessControl() == null) target.setAccessControl(new ProxyAccessControl());
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/**
2+
* ContainerProxy
3+
*
4+
* Copyright (C) 2016-2021 Open Analytics
5+
*
6+
* ===========================================================================
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the Apache License as published by
10+
* The Apache Software Foundation, either version 2 of the License, or
11+
* (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* Apache License for more details.
17+
*
18+
* You should have received a copy of the Apache License
19+
* along with this program. If not, see <http://www.apache.org/licenses/>
20+
*/
21+
package eu.openanalytics.containerproxy.service;
22+
23+
import eu.openanalytics.containerproxy.model.runtime.Proxy;
24+
import eu.openanalytics.containerproxy.model.runtime.ProxyStatus;
25+
import org.apache.commons.lang.time.DurationFormatUtils;
26+
import org.apache.logging.log4j.LogManager;
27+
import org.apache.logging.log4j.Logger;
28+
import org.springframework.core.env.Environment;
29+
import org.springframework.stereotype.Service;
30+
31+
import javax.annotation.PostConstruct;
32+
import javax.inject.Inject;
33+
import java.time.Instant;
34+
import java.time.temporal.ChronoUnit;
35+
import java.util.Timer;
36+
import java.util.TimerTask;
37+
38+
/**
39+
* This service releases proxies which reached their max-lifetime.
40+
*/
41+
@Service
42+
public class ProxyMaxLifetimeService {
43+
44+
private static final Integer CLEANUP_INTERVAL = 5 * 60 * 1000;
45+
private static final String PROP_DEFAULT_PROXY_MAX_LIFETIME = "proxy.default-proxy-max-lifetime";
46+
47+
private final Logger log = LogManager.getLogger(ProxyMaxLifetimeService.class);
48+
49+
@Inject
50+
private ProxyService proxyService;
51+
52+
@Inject
53+
private Environment environment;
54+
55+
private Long defaultMaxLifetime;
56+
57+
@PostConstruct
58+
public void init() {
59+
defaultMaxLifetime = environment.getProperty(PROP_DEFAULT_PROXY_MAX_LIFETIME, Long.class, -1L);
60+
61+
new Timer().schedule(new TimerTask() {
62+
@Override
63+
public void run() {
64+
performCleanup();
65+
}
66+
}, CLEANUP_INTERVAL, CLEANUP_INTERVAL);
67+
}
68+
69+
private void performCleanup() {
70+
for (Proxy proxy : proxyService.getProxies(null, true)) {
71+
if (mustBeReleased(proxy)) {
72+
String uptime = DurationFormatUtils.formatDurationWords(
73+
System.currentTimeMillis() - proxy.getCreatedTimestamp(),
74+
true, false);
75+
log.info(String.format("Forcefully releasing proxy because it reached the max lifetime [user: %s] [spec: %s] [id: %s] [uptime: %s]", proxy.getUserId(), proxy.getSpec().getId(), proxy.getId(), uptime));
76+
proxyService.stopProxy(proxy, true, true);
77+
}
78+
}
79+
80+
}
81+
82+
private Boolean mustBeReleased(Proxy proxy) {
83+
if (proxy.getStatus() != ProxyStatus.Up) {
84+
return false;
85+
}
86+
87+
Long maxLifeTime = proxy.getSpec().getMaxLifeTime();
88+
if (maxLifeTime == null) {
89+
maxLifeTime = defaultMaxLifetime;
90+
}
91+
92+
Instant notBeforeTime = Instant.now().minus(maxLifeTime, ChronoUnit.MINUTES);
93+
94+
return Instant.ofEpochMilli(proxy.getCreatedTimestamp()).isBefore(notBeforeTime);
95+
}
96+
97+
}

0 commit comments

Comments
 (0)