use of javax.servlet.AsyncEvent in project presto by prestodb.
the class AsyncPageTransportServlet method processRequest.
protected void processRequest(String requestURI, TaskId taskId, OutputBufferId bufferId, long token, HttpServletRequest request, HttpServletResponse response) throws IOException {
DataSize maxSize = DataSize.valueOf(request.getHeader(PRESTO_MAX_SIZE));
AsyncContext asyncContext = request.startAsync(request, response);
// wait time to get results
Duration waitTime = randomizeWaitTime(DEFAULT_MAX_WAIT_TIME);
asyncContext.setTimeout(waitTime.toMillis() + pageTransportTimeout.toMillis());
asyncContext.addListener(new AsyncListener() {
public void onComplete(AsyncEvent event) {
}
public void onError(AsyncEvent event) throws IOException {
String errorMessage = format("Server error to process task result request %s : %s", requestURI, event.getThrowable().getMessage());
log.error(event.getThrowable(), errorMessage);
response.sendError(SC_INTERNAL_SERVER_ERROR, errorMessage);
}
public void onStartAsync(AsyncEvent event) {
}
public void onTimeout(AsyncEvent event) throws IOException {
String errorMessage = format("Server timeout to process task result request: %s", requestURI);
log.error(event.getThrowable(), errorMessage);
response.sendError(SC_INTERNAL_SERVER_ERROR, errorMessage);
}
});
ListenableFuture<BufferResult> bufferResultFuture = taskManager.getTaskResults(taskId, bufferId, token, maxSize);
bufferResultFuture = addTimeout(bufferResultFuture, () -> BufferResult.emptyResults(taskManager.getTaskInstanceId(taskId), token, false), waitTime, timeoutExecutor);
ServletOutputStream out = response.getOutputStream();
addCallback(bufferResultFuture, new FutureCallback<BufferResult>() {
@Override
public void onSuccess(BufferResult bufferResult) {
response.setHeader(CONTENT_TYPE, PRESTO_PAGES);
response.setHeader(PRESTO_TASK_INSTANCE_ID, bufferResult.getTaskInstanceId());
response.setHeader(PRESTO_PAGE_TOKEN, String.valueOf(bufferResult.getToken()));
response.setHeader(PRESTO_PAGE_NEXT_TOKEN, String.valueOf(bufferResult.getNextToken()));
response.setHeader(PRESTO_BUFFER_COMPLETE, String.valueOf(bufferResult.isBufferComplete()));
List<SerializedPage> serializedPages = bufferResult.getSerializedPages();
if (serializedPages.isEmpty()) {
response.setStatus(SC_NO_CONTENT);
asyncContext.complete();
} else {
int contentLength = (serializedPages.size() * PAGE_METADATA_SIZE) + serializedPages.stream().mapToInt(SerializedPage::getSizeInBytes).sum();
response.setHeader(CONTENT_LENGTH, String.valueOf(contentLength));
out.setWriteListener(new SerializedPageWriteListener(serializedPages, asyncContext, out));
}
}
@Override
public void onFailure(Throwable thrown) {
String errorMessage = format("Error getting task result from TaskManager for request %s : %s", requestURI, thrown.getMessage());
log.error(thrown, errorMessage);
try {
response.sendError(SC_INTERNAL_SERVER_ERROR, errorMessage);
} catch (IOException e) {
log.error(e, "Failed to send response with error code: %s", e.getMessage());
}
asyncContext.complete();
}
}, responseExecutor);
}
use of javax.servlet.AsyncEvent in project java-chassis by ServiceComb.
the class TestRestAsyncListener method setup.
@Before
public void setup() {
event = new AsyncEvent(context, requestEx, response);
requestEx.setAttribute(RestConst.REST_REQUEST, requestEx);
new MockUp<HttpServletResponse>(response) {
@Mock
void setContentType(String type) {
contentType = type;
}
@Mock
void setStatus(int sc) {
statusCode = sc;
}
@Mock
boolean isCommitted() {
return committed;
}
@Mock
PrintWriter getWriter() throws IOException {
return printWriter;
}
@Mock
void flushBuffer() throws IOException {
flushed = true;
}
};
}
use of javax.servlet.AsyncEvent in project rest.li by linkedin.
the class AbstractAsyncR2StreamServlet method service.
@Override
public void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
final AsyncContext ctx = req.startAsync(req, resp);
ctx.setTimeout(_timeout);
final WrappedAsyncContext wrappedCtx = new WrappedAsyncContext(ctx);
final AsyncEventIOHandler ioHandler = new AsyncEventIOHandler(req.getInputStream(), resp.getOutputStream(), req.getRemoteAddr(), wrappedCtx, MAX_BUFFERED_CHUNKS, _logServletExceptions);
final RequestContext requestContext = ServletHelper.readRequestContext(req);
final StreamRequest streamRequest;
try {
streamRequest = ServletHelper.readFromServletRequest(req, ioHandler);
} catch (URISyntaxException e) {
ServletHelper.writeToServletError(resp, RestStatus.BAD_REQUEST, e.toString());
wrappedCtx.complete();
return;
}
final AtomicBoolean startedResponding = new AtomicBoolean(false);
ctx.addListener(new AsyncListener() {
@Override
public void onTimeout(AsyncEvent event) throws IOException {
LOG.error("Server timeout for request: " + formatURI(req.getRequestURI()));
if (startedResponding.compareAndSet(false, true)) {
LOG.info("Returning server timeout response");
ServletHelper.writeToServletError(resp, RestStatus.INTERNAL_SERVER_ERROR, "Server timeout");
} else {
req.setAttribute(ASYNC_IOEXCEPTION, new ServletException("Server timeout"));
}
ioHandler.exitLoop();
wrappedCtx.complete();
}
@Override
public void onStartAsync(AsyncEvent event) throws IOException {
// Nothing to do here
}
@Override
public void onError(AsyncEvent event) throws IOException {
LOG.error("Server error for request: " + formatURI(req.getRequestURI()));
if (startedResponding.compareAndSet(false, true)) {
LOG.info("Returning server error response");
ServletHelper.writeToServletError(resp, RestStatus.INTERNAL_SERVER_ERROR, "Server error");
} else {
req.setAttribute(ASYNC_IOEXCEPTION, new ServletException("Server error"));
}
ioHandler.exitLoop();
wrappedCtx.complete();
}
@Override
public void onComplete(AsyncEvent event) throws IOException {
Object exception = req.getAttribute(ASYNC_IOEXCEPTION);
if (exception != null) {
throw new IOException((Throwable) exception);
}
}
});
final TransportCallback<StreamResponse> callback = new TransportCallback<StreamResponse>() {
@Override
public void onResponse(final TransportResponse<StreamResponse> response) {
if (startedResponding.compareAndSet(false, true)) {
ctx.start(new Runnable() {
@Override
public void run() {
try {
StreamResponse streamResponse = ServletHelper.writeResponseHeadersToServletResponse(response, resp);
streamResponse.getEntityStream().setReader(ioHandler);
ioHandler.loop();
} catch (Exception e) {
req.setAttribute(ASYNC_IOEXCEPTION, e);
wrappedCtx.complete();
}
}
});
} else {
LOG.error("Dropped a response; this is mostly like because that AsyncContext timeout or error had already happened");
}
}
};
// we have to use a new thread and let this thread return to pool. otherwise the timeout won't start
ctx.start(new Runnable() {
@Override
public void run() {
try {
getDispatcher().handleRequest(streamRequest, requestContext, callback);
ioHandler.loop();
} catch (Exception e) {
req.setAttribute(ASYNC_IOEXCEPTION, e);
wrappedCtx.complete();
}
}
});
}
use of javax.servlet.AsyncEvent in project druid by druid-io.
the class SegmentListerResource method applyDataSegmentChangeRequests.
/**
* This endpoint is used by HttpLoadQueuePeon to assign segment load/drop requests batch. This endpoint makes the
* client wait till one of the following events occur. Note that this is implemented using async IO so no jetty
* threads are held while in wait.
*
* (1) Given timeout elapses.
* (2) Some load/drop request completed.
*
* It returns a map of "load/drop request -> SUCCESS/FAILED/PENDING status" for each request in the batch.
*/
@POST
@Path("/changeRequests")
@Produces({ MediaType.APPLICATION_JSON, SmileMediaTypes.APPLICATION_JACKSON_SMILE })
@Consumes({ MediaType.APPLICATION_JSON, SmileMediaTypes.APPLICATION_JACKSON_SMILE })
public void applyDataSegmentChangeRequests(@QueryParam("timeout") long timeout, List<DataSegmentChangeRequest> changeRequestList, @Context final HttpServletRequest req) throws IOException {
if (loadDropRequestHandler == null) {
sendErrorResponse(req, HttpServletResponse.SC_NOT_FOUND, "load/drop handler is not available.");
return;
}
if (timeout <= 0) {
sendErrorResponse(req, HttpServletResponse.SC_BAD_REQUEST, "timeout must be positive.");
return;
}
if (changeRequestList == null || changeRequestList.isEmpty()) {
sendErrorResponse(req, HttpServletResponse.SC_BAD_REQUEST, "No change requests provided.");
return;
}
final ResponseContext context = createContext(req.getHeader("Accept"));
final ListenableFuture<List<SegmentLoadDropHandler.DataSegmentChangeRequestAndStatus>> future = loadDropRequestHandler.processBatch(changeRequestList);
final AsyncContext asyncContext = req.startAsync();
asyncContext.addListener(new AsyncListener() {
@Override
public void onComplete(AsyncEvent event) {
}
@Override
public void onTimeout(AsyncEvent event) {
// HTTP 204 NO_CONTENT is sent to the client.
future.cancel(true);
event.getAsyncContext().complete();
}
@Override
public void onError(AsyncEvent event) {
}
@Override
public void onStartAsync(AsyncEvent event) {
}
});
Futures.addCallback(future, new FutureCallback<List<SegmentLoadDropHandler.DataSegmentChangeRequestAndStatus>>() {
@Override
public void onSuccess(List<SegmentLoadDropHandler.DataSegmentChangeRequestAndStatus> result) {
try {
HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse();
response.setStatus(HttpServletResponse.SC_OK);
context.inputMapper.writerWithType(HttpLoadQueuePeon.RESPONSE_ENTITY_TYPE_REF).writeValue(asyncContext.getResponse().getOutputStream(), result);
asyncContext.complete();
} catch (Exception ex) {
log.debug(ex, "Request timed out or closed already.");
}
}
@Override
public void onFailure(Throwable th) {
try {
HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse();
if (th instanceof IllegalArgumentException) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, th.getMessage());
} else {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, th.getMessage());
}
asyncContext.complete();
} catch (Exception ex) {
log.debug(ex, "Request timed out or closed already.");
}
}
});
asyncContext.setTimeout(timeout);
}
use of javax.servlet.AsyncEvent in project druid by druid-io.
the class TaskManagementResource method getWorkerState.
/**
* This endpoint is used by HttpRemoteTaskRunner to keep an up-to-date state of the worker wrt to the tasks it is
* running, completed etc and other metadata such as its enabled/disabled status.
*
* Here is how, this is used.
*
* (1) Client sends first request /druid/internal/v1/worker?counter=-1&timeout=<timeout>
* Server responds with current list of running/completed tasks and metadata. And, a <counter,hash> pair.
*
* (2) Client sends subsequent requests /druid/internal/v1/worker?counter=<counter>&hash=<hash>&timeout=<timeout>
* Where <counter,hash> values are used from the last response. Server responds with changes since then.
*
* This endpoint makes the client wait till either there is some update or given timeout elapses.
*
* So, clients keep on sending next request immediately after receiving the response in order to keep the state of
* this server up-to-date.
*
* @param counter counter received in last response.
* @param hash hash received in last response.
* @param timeout after which response is sent even if there are no new segment updates.
* @param req
* @return null to avoid "MUST return a non-void type" warning.
* @throws IOException
*/
@GET
@Produces({ MediaType.APPLICATION_JSON, SmileMediaTypes.APPLICATION_JACKSON_SMILE })
public Void getWorkerState(@QueryParam("counter") long counter, @QueryParam("hash") long hash, @QueryParam("timeout") long timeout, @Context final HttpServletRequest req) throws IOException {
if (timeout <= 0) {
sendErrorResponse(req, HttpServletResponse.SC_BAD_REQUEST, "timeout must be positive.");
return null;
}
final ResponseContext context = createContext(req.getHeader("Accept"));
final ListenableFuture<ChangeRequestsSnapshot<WorkerHistoryItem>> future = workerTaskManager.getChangesSince(new ChangeRequestHistory.Counter(counter, hash));
final AsyncContext asyncContext = req.startAsync();
asyncContext.addListener(new AsyncListener() {
@Override
public void onComplete(AsyncEvent event) {
}
@Override
public void onTimeout(AsyncEvent event) {
// HTTP 204 NO_CONTENT is sent to the client.
future.cancel(true);
event.getAsyncContext().complete();
}
@Override
public void onError(AsyncEvent event) {
}
@Override
public void onStartAsync(AsyncEvent event) {
}
});
Futures.addCallback(future, new FutureCallback<ChangeRequestsSnapshot>() {
@Override
public void onSuccess(ChangeRequestsSnapshot result) {
try {
HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse();
response.setStatus(HttpServletResponse.SC_OK);
context.inputMapper.writerWithType(WorkerHolder.WORKER_SYNC_RESP_TYPE_REF).writeValue(asyncContext.getResponse().getOutputStream(), result);
asyncContext.complete();
} catch (Exception ex) {
log.debug(ex, "Request timed out or closed already.");
}
}
@Override
public void onFailure(Throwable th) {
try {
HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse();
if (th instanceof IllegalArgumentException) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, th.getMessage());
} else {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, th.getMessage());
}
asyncContext.complete();
} catch (Exception ex) {
log.debug(ex, "Request timed out or closed already.");
}
}
});
asyncContext.setTimeout(timeout);
return null;
}
Aggregations