use of com.netflix.zuul.stats.status.StatusCategory in project zuul by Netflix.
the class ClientResponseWriter method channelRead.
@Override
public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
final Channel channel = ctx.channel();
if (msg instanceof HttpResponseMessage) {
final HttpResponseMessage resp = (HttpResponseMessage) msg;
if (skipProcessing(resp)) {
return;
}
if ((!isHandlingRequest) || (startedSendingResponseToClient)) {
/* This can happen if we are already in the process of streaming response back to client OR NOT within active
request/response cycle and something like IDLE or Request Read timeout occurs. In that case we have no way
to recover other than closing the socket and cleaning up resources used by BOTH responses.
*/
resp.disposeBufferedBody();
if (zuulResponse != null)
zuulResponse.disposeBufferedBody();
// This will trigger CompleteEvent if one is needed
ctx.close();
return;
}
startedSendingResponseToClient = true;
zuulResponse = resp;
if ("close".equalsIgnoreCase(zuulResponse.getHeaders().getFirst("Connection"))) {
closeConnection = true;
}
channel.attr(ATTR_ZUUL_RESP).set(zuulResponse);
if (channel.isActive()) {
// Track if this is happening.
if (!ClientRequestReceiver.isLastContentReceivedForChannel(channel)) {
StatusCategory status = StatusCategoryUtils.getStatusCategory(ClientRequestReceiver.getRequestFromChannel(channel));
if (ZuulStatusCategory.FAILURE_CLIENT_TIMEOUT.equals(status)) {
// If the request timed-out while being read, then there won't have been any LastContent, but thats ok because the connection will have to be discarded anyway.
} else {
responseBeforeReceivedLastContentCounter.increment();
LOG.warn("Writing response to client channel before have received the LastContent of request! " + zuulResponse.getInboundRequest().getInfoForLogging() + ", " + ChannelUtils.channelInfoForLogging(channel));
}
}
// Write out and flush the response to the client channel.
channel.write(buildHttpResponse(zuulResponse));
writeBufferedBodyContent(zuulResponse, channel);
channel.flush();
} else {
channel.close();
}
} else if (msg instanceof HttpContent) {
final HttpContent chunk = (HttpContent) msg;
if (channel.isActive()) {
channel.writeAndFlush(chunk);
} else {
chunk.release();
channel.close();
}
} else {
// should never happen
ReferenceCountUtil.release(msg);
throw new ZuulException("Received invalid message from origin", true);
}
}
use of com.netflix.zuul.stats.status.StatusCategory in project zuul by Netflix.
the class BasicNettyOrigin method recordFinalResponse.
@Override
public void recordFinalResponse(HttpResponseMessage resp) {
if (resp != null) {
final SessionContext zuulCtx = resp.getContext();
// Store the status code of final attempt response.
int originStatusCode = resp.getStatus();
zuulCtx.put(CommonContextKeys.ORIGIN_STATUS, originStatusCode);
// Mark origin StatusCategory based on http status code.
StatusCategory originNfs = SUCCESS;
if (originStatusCode == 503) {
originNfs = FAILURE_ORIGIN_THROTTLED;
} else if (StatusCategoryUtils.isResponseHttpErrorStatus(originStatusCode)) {
originNfs = FAILURE_ORIGIN;
}
zuulCtx.put(CommonContextKeys.ORIGIN_STATUS_CATEGORY, originNfs);
// Choose the zuul StatusCategory based on the origin one...
// ... but only if existing one has not already been set to a non-success value.
StatusCategoryUtils.storeStatusCategoryIfNotAlreadyFailure(zuulCtx, originNfs);
}
}
use of com.netflix.zuul.stats.status.StatusCategory in project zuul by Netflix.
the class BasicNettyOrigin method recordFinalError.
@Override
public void recordFinalError(HttpRequestMessage requestMsg, Throwable throwable) {
if (throwable == null) {
return;
}
final SessionContext zuulCtx = requestMsg.getContext();
// Choose StatusCategory based on the ErrorType.
final ErrorType et = requestAttemptFactory.mapNettyToOutboundErrorType(throwable);
final StatusCategory nfs = et.getStatusCategory();
zuulCtx.put(CommonContextKeys.STATUS_CATGEORY, nfs);
zuulCtx.put(CommonContextKeys.ORIGIN_STATUS_CATEGORY, nfs);
zuulCtx.setError(throwable);
}
use of com.netflix.zuul.stats.status.StatusCategory in project zuul by Netflix.
the class ProxyEndpoint method handleOriginSuccessResponse.
protected void handleOriginSuccessResponse(final HttpResponse originResponse, DiscoveryResult chosenServer) {
origin.recordSuccessResponse();
if (originConn != null) {
originConn.getServer().clearSuccessiveConnectionFailureCount();
}
final int respStatus = originResponse.status().code();
long duration = 0;
if (currentRequestStat != null) {
currentRequestStat.updateWithHttpStatusCode(respStatus);
duration = currentRequestStat.duration();
}
if (currentRequestAttempt != null) {
currentRequestAttempt.complete(respStatus, duration, null);
}
// separate nfstatus for 404 so that we can notify origins
final StatusCategory statusCategory = respStatus == 404 ? SUCCESS_NOT_FOUND : SUCCESS;
zuulResponse = buildZuulHttpResponse(originResponse, statusCategory, context.getError());
invokeNext(zuulResponse);
}
use of com.netflix.zuul.stats.status.StatusCategory in project zuul by Netflix.
the class ProxyEndpoint method handleOriginNonSuccessResponse.
protected void handleOriginNonSuccessResponse(final HttpResponse originResponse, DiscoveryResult chosenServer) {
final int respStatus = originResponse.status().code();
OutboundException obe;
StatusCategory statusCategory;
ClientException.ErrorType niwsErrorType;
if (respStatus == 503) {
// Treat 503 status from Origin similarly to connection failures, ie. we want to back off from this server
statusCategory = FAILURE_ORIGIN_THROTTLED;
niwsErrorType = ClientException.ErrorType.SERVER_THROTTLED;
obe = new OutboundException(OutboundErrorType.SERVICE_UNAVAILABLE, requestAttempts);
// TODO(carl-mastrangelo): pass in the clock for testing.
origin.stats().lastThrottleEvent(ZonedDateTime.now());
if (originConn != null) {
originConn.getServer().incrementSuccessiveConnectionFailureCount();
originConn.getServer().addToFailureCount();
originConn.flagShouldClose();
}
if (currentRequestStat != null) {
currentRequestStat.updateWithHttpStatusCode(respStatus);
currentRequestStat.serviceUnavailable();
}
} else {
statusCategory = FAILURE_ORIGIN;
niwsErrorType = ClientException.ErrorType.GENERAL;
obe = new OutboundException(OutboundErrorType.ERROR_STATUS_RESPONSE, requestAttempts);
if (currentRequestStat != null) {
currentRequestStat.updateWithHttpStatusCode(respStatus);
currentRequestStat.generalError();
}
}
obe.setStatusCode(respStatus);
long duration = 0;
if (currentRequestStat != null) {
duration = currentRequestStat.duration();
}
if (currentRequestAttempt != null) {
currentRequestAttempt.complete(respStatus, duration, obe);
}
// Flag this error with the ExecutionListener.
origin.onRequestExceptionWithServer(zuulRequest, chosenServer, attemptNum, new ClientException(niwsErrorType));
if ((isBelowRetryLimit()) && (isRetryable5xxResponse(zuulRequest, originResponse))) {
LOG.debug("Retrying: status={}, attemptNum={}, maxRetries={}, startedSendingResponseToClient={}, hasCompleteBody={}, method={}", respStatus, attemptNum, origin.getMaxRetriesForRequest(context), startedSendingResponseToClient, zuulRequest.hasCompleteBody(), zuulRequest.getMethod());
// detach from current origin.
unlinkFromOrigin();
// retry request with different origin
passport.add(ORIGIN_RETRY_START);
origin.adjustRetryPolicyIfNeeded(zuulRequest);
proxyRequestToOrigin();
} else {
SessionContext zuulCtx = context;
LOG.info("Sending error to client: status={}, attemptNum={}, maxRetries={}, startedSendingResponseToClient={}, hasCompleteBody={}, method={}", respStatus, attemptNum, origin.getMaxRetriesForRequest(zuulCtx), startedSendingResponseToClient, zuulRequest.hasCompleteBody(), zuulRequest.getMethod());
// This is a final response after all retries that will go to the client
zuulResponse = buildZuulHttpResponse(originResponse, statusCategory, obe);
invokeNext(zuulResponse);
}
}
Aggregations