Skip to content

Commit 38bbfc1

Browse files
committed
Merge branch 'develop' into feature/27504/aws
2 parents 5fba26c + 95398d2 commit 38bbfc1

File tree

3 files changed

+76
-11
lines changed

3 files changed

+76
-11
lines changed

src/main/java/eu/openanalytics/containerproxy/api/ProxyRouteController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public void route(HttpServletRequest request, HttpServletResponse response) {
6262
}
6363

6464
if (hasAccess) {
65-
mappingManager.dispatchAsync(mapping, request, response);
65+
mappingManager.dispatchAsync(proxyId, mapping, request, response);
6666
} else {
6767
response.setStatus(403);
6868
response.getWriter().write("Not authorized to access this proxy");

src/main/java/eu/openanalytics/containerproxy/service/ProxyService.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,8 @@
4141
import eu.openanalytics.containerproxy.spec.expression.SpecExpressionContext;
4242
import eu.openanalytics.containerproxy.spec.expression.SpecExpressionResolver;
4343
import eu.openanalytics.containerproxy.util.ProxyMappingManager;
44-
import org.slf4j.Logger;
45-
import org.slf4j.LoggerFactory;
4644
import org.springframework.context.ApplicationEventPublisher;
45+
import org.springframework.context.annotation.Lazy;
4746
import org.springframework.core.env.Environment;
4847
import org.springframework.data.util.Pair;
4948
import org.springframework.security.access.AccessDeniedException;
@@ -520,7 +519,6 @@ private boolean cleanupIfPendingAppWasStopped(Proxy startingProxy) {
520519
return false;
521520
}
522521

523-
524522
/**
525523
* Add existing Proxy to the ProxyService.
526524
* This is used by the AppRecovery feature.

src/main/java/eu/openanalytics/containerproxy/util/ProxyMappingManager.java

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,14 @@
2020
*/
2121
package eu.openanalytics.containerproxy.util;
2222

23+
import eu.openanalytics.containerproxy.model.runtime.Proxy;
24+
import eu.openanalytics.containerproxy.model.runtime.ProxyStatus;
25+
import eu.openanalytics.containerproxy.service.AsyncProxyService;
26+
import eu.openanalytics.containerproxy.service.ProxyService;
27+
import eu.openanalytics.containerproxy.service.StructuredLogger;
2328
import eu.openanalytics.containerproxy.service.hearbeat.HeartbeatService;
29+
import io.undertow.io.Sender;
30+
import io.undertow.server.DefaultResponseListener;
2431
import io.undertow.server.HttpHandler;
2532
import io.undertow.server.HttpServerExchange;
2633
import io.undertow.server.handlers.PathHandler;
@@ -31,8 +38,10 @@
3138
import io.undertow.server.handlers.proxy.ProxyHandler;
3239
import io.undertow.servlet.handlers.ServletRequestContext;
3340
import io.undertow.util.AttachmentKey;
41+
import io.undertow.util.Headers;
3442
import io.undertow.util.PathMatcher;
3543
import org.springframework.context.annotation.Lazy;
44+
import io.undertow.util.StatusCodes;
3645
import org.springframework.stereotype.Component;
3746

3847
import javax.inject.Inject;
@@ -58,15 +67,26 @@ public class ProxyMappingManager {
5867

5968
private static final String PROXY_INTERNAL_ENDPOINT = "/proxy_endpoint";
6069
private static final AttachmentKey<ProxyMappingManager> ATTACHMENT_KEY_DISPATCHER = AttachmentKey.create(ProxyMappingManager.class);
61-
70+
private static final AttachmentKey<ProxyIdAttachment> ATTACHMENT_KEY_PROXY_ID = AttachmentKey.create(ProxyIdAttachment.class);
71+
72+
private final StructuredLogger logger = StructuredLogger.create(getClass());
73+
6274
private PathHandler pathHandler;
6375

6476
private final Map<String, String> mappings = new HashMap<>();
6577

6678
@Inject
6779
@Lazy
6880
private HeartbeatService heartbeatService;
69-
81+
82+
@Inject
83+
@Lazy
84+
private ProxyService proxyService;
85+
86+
@Inject
87+
@Lazy
88+
private AsyncProxyService asyncProxyService;
89+
7090
public synchronized HttpHandler createHttpHandler(HttpHandler defaultHandler) {
7191
if (pathHandler == null) {
7292
pathHandler = new ProxyPathHandler(defaultHandler);
@@ -123,32 +143,70 @@ public String getProxyId(String mapping) {
123143
*
124144
* Note that clients can never access a proxy handler directly (for security reasons).
125145
* Dispatching is the only allowed method to access proxy handlers.
126-
*
146+
*
147+
* @param proxyId The id of the proxy
127148
* @param mapping The target mapping to dispatch to.
128149
* @param request The request to dispatch.
129150
* @param response The response corresponding to the request.
130151
* @throws IOException If the dispatch fails for an I/O reason.
131152
* @throws ServletException If the dispatch fails for any other reason.
132153
*/
133-
public void dispatchAsync(String mapping, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
134-
dispatchAsync(mapping, request, response, null);
154+
public void dispatchAsync(String proxyId, String mapping, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
155+
dispatchAsync(proxyId, mapping, request, response, null);
135156
}
136157

137-
public void dispatchAsync(String mapping, HttpServletRequest request, HttpServletResponse response, Consumer<HttpServerExchange> exchangeCustomizer) throws IOException, ServletException {
158+
public void dispatchAsync(String proxyId, String mapping, HttpServletRequest request, HttpServletResponse response, Consumer<HttpServerExchange> exchangeCustomizer) throws IOException, ServletException {
138159
HttpServerExchange exchange = ServletRequestContext.current().getExchange();
139160
exchange.putAttachment(ATTACHMENT_KEY_DISPATCHER, this);
140-
161+
exchange.putAttachment(ATTACHMENT_KEY_PROXY_ID, new ProxyIdAttachment(proxyId));
162+
141163
String queryString = request.getQueryString();
142164
queryString = (queryString == null) ? "" : "?" + queryString;
143165
String targetPath = PROXY_INTERNAL_ENDPOINT + "/" + mapping + queryString;
144166

145167
if (exchangeCustomizer != null) {
146168
exchangeCustomizer.accept(exchange);
147169
}
170+
exchange.addDefaultResponseListener(defaultResponseListener);
148171
request.startAsync();
149172
request.getRequestDispatcher(targetPath).forward(request, response);
150173
}
151174

175+
private final DefaultResponseListener defaultResponseListener = responseExchange -> {
176+
if (!responseExchange.isResponseChannelAvailable()) {
177+
return false;
178+
}
179+
if (responseExchange.getStatusCode() == StatusCodes.SERVICE_UNAVAILABLE) {
180+
ProxyIdAttachment proxyIdAttachment = responseExchange.getAttachment(ATTACHMENT_KEY_PROXY_ID);
181+
Proxy proxy = null;
182+
if (proxyIdAttachment != null) {
183+
try {
184+
proxy = proxyService.getProxy(proxyIdAttachment.proxyId);
185+
if (proxy != null) {
186+
logger.info(proxy, "Proxy unreachable/crashed, stopping it now");
187+
asyncProxyService.stopProxy(proxy, true);
188+
}
189+
} catch (Throwable t) {
190+
// ignore in order to complete request
191+
}
192+
}
193+
194+
String errorPage;
195+
if (proxy != null && proxy.getStatus() != ProxyStatus.Stopped) {
196+
errorPage = "{\"status\":\"error\", \"message\":\"app_crashed\"}";
197+
} else {
198+
// in-progress request got terminated because the app has been stopped (not crashed)
199+
errorPage = "{\"status\":\"error\", \"message\":\"app_stopped_or_non_existent\"}";
200+
}
201+
responseExchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, "" + errorPage.length());
202+
responseExchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json");
203+
Sender sender = responseExchange.getResponseSender();
204+
sender.send(errorPage);
205+
return true;
206+
}
207+
return false;
208+
};
209+
152210
private static class ProxyPathHandler extends PathHandler {
153211

154212
public ProxyPathHandler(HttpHandler defaultHandler) {
@@ -173,4 +231,13 @@ public void handleRequest(HttpServerExchange exchange) throws Exception {
173231
}
174232
}
175233
}
234+
235+
private static class ProxyIdAttachment {
236+
final String proxyId;
237+
238+
public ProxyIdAttachment(String proxyId) {
239+
this.proxyId = proxyId;
240+
}
241+
}
242+
176243
}

0 commit comments

Comments
 (0)