org.swisspush.redisques.handler.RedisquesHttpRequestHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of redisques Show documentation
Show all versions of redisques Show documentation
A highly scalable redis-persistent queuing system for vertx
package org.swisspush.redisques.handler;
import io.netty.util.internal.StringUtil;
import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.eventbus.Message;
import io.vertx.core.eventbus.ReplyException;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.auth.authentication.AuthenticationProvider;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BasicAuthHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.swisspush.redisques.QueueStatsService;
import org.swisspush.redisques.QueueStatsService.GetQueueStatsMentor;
import org.swisspush.redisques.exception.RedisQuesExceptionFactory;
import org.swisspush.redisques.util.DequeueStatisticCollector;
import org.swisspush.redisques.util.QueueStatisticsCollector;
import org.swisspush.redisques.util.RedisquesAPI;
import org.swisspush.redisques.util.RedisquesConfiguration;
import org.swisspush.redisques.util.Result;
import org.swisspush.redisques.util.StatusCode;
import javax.annotation.Nullable;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Semaphore;
import java.util.stream.Collectors;
import static org.swisspush.redisques.util.HttpServerRequestUtil.*;
import static org.swisspush.redisques.util.RedisquesAPI.*;
/**
* Handler class for HTTP requests providing access to Redisques over HTTP.
*
* @author Marc-André Weber
*/
public class RedisquesHttpRequestHandler implements Handler {
private static final Logger log = LoggerFactory.getLogger(RedisquesHttpRequestHandler.class);
private final Vertx vertx;
private final Router router;
private final EventBus eventBus;
private static final String APPLICATION_JSON = "application/json";
private static final String TEXT_PLAIN = "text/plain";
private static final String CONTENT_TYPE = "content-type";
private static final String LOCKED_PARAM = "locked";
private static final String UNLOCK_PARAM = "unlock";
private static final String BULK_DELETE_PARAM = "bulkDelete";
private static final String EMPTY_QUEUES_PARAM = "emptyQueues";
private static final String DELETED = "deleted";
/**
* @deprecated about obsolete date formats
*/
@Deprecated
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
private final String redisquesAddress;
private final String userHeader;
private final boolean enableQueueNameDecoding;
private final int queueSpeedIntervalSec;
private final QueueStatisticsCollector queueStatisticsCollector;
private final RedisQuesExceptionFactory exceptionFactory;
private final QueueStatsService queueStatsService;
private final GetQueueStatsMentor queueStatsMentor = new MyQueueStatsMentor();
public static void init(
Vertx vertx, RedisquesConfiguration modConfig, QueueStatisticsCollector queueStatisticsCollector,
DequeueStatisticCollector dequeueStatisticCollector, RedisQuesExceptionFactory exceptionFactory,
Semaphore queueStatsRequestQuota
) {
log.info("Enabling http request handler: {}", modConfig.getHttpRequestHandlerEnabled());
if (modConfig.getHttpRequestHandlerEnabled()) {
if (modConfig.getHttpRequestHandlerPort() != null && modConfig.getHttpRequestHandlerUserHeader() != null) {
var handler = new RedisquesHttpRequestHandler(
vertx, modConfig, queueStatisticsCollector, dequeueStatisticCollector,
exceptionFactory, queueStatsRequestQuota);
// in Vert.x 2x 100-continues was activated per default, in vert.x 3x it is off per default.
HttpServerOptions options = new HttpServerOptions().setHandle100ContinueAutomatically(true);
vertx.createHttpServer(options).requestHandler(handler).listen(modConfig.getHttpRequestHandlerPort(), result -> {
if (result.succeeded()) {
log.info("Successfully started http request handler on port {}", modConfig.getHttpRequestHandlerPort());
} else {
log.error("Unable to start http request handler.", result.cause());
}
});
} else {
log.error("Configured to enable http request handler but no port configuration and/or user header configuration provided");
}
}
}
private Result checkHttpAuthenticationConfiguration(RedisquesConfiguration modConfig) {
if (modConfig.getHttpRequestHandlerAuthenticationEnabled()) {
if (StringUtil.isNullOrEmpty(modConfig.getHttpRequestHandlerUsername()) ||
StringUtil.isNullOrEmpty(modConfig.getHttpRequestHandlerPassword())) {
String msg = "HTTP API authentication is enabled but username and/or password is missing";
log.warn(msg);
return Result.err(msg);
}
return Result.ok(true);
}
return Result.ok(false);
}
private RedisquesHttpRequestHandler(
Vertx vertx,
RedisquesConfiguration modConfig,
QueueStatisticsCollector queueStatisticsCollector,
DequeueStatisticCollector dequeueStatisticCollector,
RedisQuesExceptionFactory exceptionFactory,
Semaphore queueStatsRequestQuota
) {
this.vertx = vertx;
this.router = Router.router(vertx);
this.eventBus = vertx.eventBus();
this.redisquesAddress = modConfig.getAddress();
this.userHeader = modConfig.getHttpRequestHandlerUserHeader();
this.enableQueueNameDecoding = modConfig.getEnableQueueNameDecoding();
this.queueSpeedIntervalSec = modConfig.getQueueSpeedIntervalSec();
this.queueStatisticsCollector = queueStatisticsCollector;
this.exceptionFactory = exceptionFactory;
this.queueStatsService = new QueueStatsService(
vertx, eventBus, redisquesAddress, queueStatisticsCollector, dequeueStatisticCollector,
exceptionFactory, queueStatsRequestQuota);
final String prefix = modConfig.getHttpRequestHandlerPrefix();
Result result = checkHttpAuthenticationConfiguration(modConfig);
if (result.isErr()) {
router.route().handler(ctx -> respondWith(StatusCode.INTERNAL_SERVER_ERROR, result.getErr(), ctx.request()));
} else if (result.getOk()) {
AuthenticationProvider authProvider = new RedisquesConfigurationAuthentication(modConfig);
router.route().handler(BasicAuthHandler.create(authProvider));
log.info("Authentication enabled for HTTP API");
}
/*
* List endpoints
*/
router.get(prefix).handler(this::listEndpoints);
/*
* Get configuration
*/
router.get(prefix + "/configuration").handler(this::getConfiguration);
/*
* Set configuration
*/
router.post(prefix + "/configuration").handler(this::setConfiguration);
/*
* Get monitor information
*/
router.get(prefix + "/monitor").handler(this::getMonitorInformation);
/*
* Get statistic information
*/
router.get(prefix + "/statistics").handler(this::getQueuesStatistics);
/*
* Get queue speed information
*/
router.get(prefix + "/speed").handler(this::getQueuesSpeed);
/*
* Enqueue or LockedEnqueue
*/
router.putWithRegex(prefix + "/enqueue/([^/]+)/").handler(this::enqueueOrLockedEnqueue);
/*
* List queue items
*/
router.getWithRegex(prefix + "/monitor/[^/]+").handler(this::listQueueItems);
/*
* List or count queues
*/
router.get(prefix + "/queues").handler(this::listOrCountQueues);
/*
* List or count queue items
*/
router.getWithRegex(prefix + "/queues/[^/]+").handler(this::listOrCountQueueItems);
/*
* Delete all queue items
*/
router.deleteWithRegex(prefix + "/queues/[^/]+").handler(this::deleteAllQueueItems);
/*
* Bulk delete queues
*/
router.post(prefix + "/queues").handler(this::bulkDeleteQueues);
/*
* Get single queue item
*/
router.getWithRegex(prefix + "/queues/([^/]+)/[0-9]+").handler(this::getSingleQueueItem);
/*
* Replace single queue item
*/
router.putWithRegex(prefix + "/queues/([^/]+)/[0-9]+").handler(this::replaceSingleQueueItem);
/*
* Delete single queue item
*/
router.deleteWithRegex(prefix + "/queues/([^/]+)/[0-9]+").handler(this::deleteQueueItem);
/*
* Add queue item
*/
router.postWithRegex(prefix + "/queues/([^/]+)/").handler(this::addQueueItem);
/*
* Get all locks
*/
router.get(prefix + "/locks").handler(this::getAllLocks);
/*
* Add lock
*/
router.putWithRegex(prefix + "/locks/[^/]+").handler(this::addLock);
/*
* Get single lock
*/
router.getWithRegex(prefix + "/locks/[^/]+").handler(this::getSingleLock);
/*
* Delete all locks
*/
router.delete(prefix + "/locks").handler(this::deleteAllLocks);
/*
* Bulk create / delete locks
*/
router.post(prefix + "/locks").handler(this::bulkPutOrDeleteLocks);
/*
* Delete single lock
*/
router.deleteWithRegex(prefix + "/locks/[^/]+").handler(this::deleteSingleLock);
router.routeWithRegex(".*").handler(this::respondMethodNotAllowed);
}
@Override
public void handle(HttpServerRequest request) {
router.handle(request);
}
private void respondMethodNotAllowed(RoutingContext ctx) {
respondWith(StatusCode.METHOD_NOT_ALLOWED, ctx.request());
}
private void listEndpoints(RoutingContext ctx) {
JsonObject result = new JsonObject();
JsonArray items = new JsonArray();
items.add("locks/");
items.add("queues/");
items.add("monitor/");
items.add("configuration/");
result.put(lastPart(ctx.request().path()), items);
ctx.response().putHeader(CONTENT_TYPE, APPLICATION_JSON);
ctx.response().end(result.encode());
}
private void enqueueOrLockedEnqueue(RoutingContext ctx) {
decodedQueueNameOrRespondWithBadRequest(ctx, lastPart(ctx.request().path())).ifPresent(
queue -> ctx.request().bodyHandler(buffer -> {
try {
String strBuffer = encodePayload(buffer.toString());
eventBus.request(redisquesAddress, buildEnqueueOrLockedEnqueueOperation(queue, strBuffer, ctx.request()),
(Handler>>) reply -> {
if (reply.failed()) {
log.warn("Received failed message for enqueueOrLockedEnqueue. But will continue anyway", reply.cause());
// We should respond with 'HTTP 5xx' here. But we don't, to keep backward compatibility.
// Why we should? See: "https://softwareengineering.stackexchange.com/a/190535"
}
checkReply(reply.result(), ctx.request(), StatusCode.BAD_REQUEST);
}
);
} catch (Exception ex) {
respondWith(StatusCode.BAD_REQUEST, ex.getMessage(), ctx.request());
}
}));
}
private JsonObject buildEnqueueOrLockedEnqueueOperation(String queue, String message, HttpServerRequest request) {
if (evaluateUrlParameterToBeEmptyOrTrue(LOCKED_PARAM, request)) {
return buildLockedEnqueueOperation(queue, message, extractUser(request));
} else {
return buildEnqueueOperation(queue, message);
}
}
private void getAllLocks(RoutingContext ctx) {
String filter = ctx.request().params().get(FILTER);
eventBus.request(redisquesAddress, buildGetAllLocksOperation(filter), (Handler>>) reply -> {
if (reply.failed()) {
log.warn("Received failed message for getAllLocksOperation", exceptionFactory.newException(reply.cause()));
respondWith(StatusCode.INTERNAL_SERVER_ERROR, reply.cause().getMessage(), ctx.request());
return;
}
final JsonObject body = reply.result().body();
if (OK.equals(body.getString(STATUS))) {
jsonResponse(ctx.response(), body.getJsonObject(VALUE));
} else {
String errorType = body.getString(ERROR_TYPE);
if (BAD_INPUT.equalsIgnoreCase(errorType)) {
if (body.getString(MESSAGE) != null) {
respondWith(StatusCode.BAD_REQUEST, body.getString(MESSAGE), ctx.request());
} else {
respondWith(StatusCode.BAD_REQUEST, ctx.request());
}
} else {
respondWith(StatusCode.NOT_FOUND, ctx.request());
}
}
});
}
private void addLock(RoutingContext ctx) {
decodedQueueNameOrRespondWithBadRequest(ctx, lastPart(ctx.request().path())).ifPresent(
queue -> eventBus.request(redisquesAddress, buildPutLockOperation(queue, extractUser(ctx.request())),
(Handler>>) reply -> {
if (reply.failed()) {
String error = "Received failed message for addLockOperation";
log.warn(error, exceptionFactory.newException(reply.cause()));
respondWith(StatusCode.INTERNAL_SERVER_ERROR, error, ctx.request());
} else {
checkReply(reply.result(), ctx.request(), StatusCode.BAD_REQUEST);
}
}
));
}
private void getSingleLock(RoutingContext ctx) {
decodedQueueNameOrRespondWithBadRequest(ctx, lastPart(ctx.request().path())).ifPresent(
queue -> eventBus.request(redisquesAddress, buildGetLockOperation(queue), (Handler>>) reply -> {
final HttpServerResponse response = ctx.response();
if (reply.failed()) {
String error = "Received failed message for getSingleLockOperation";
log.warn(error, exceptionFactory.newException(reply.cause()));
respondWith(StatusCode.INTERNAL_SERVER_ERROR, error, ctx.request());
} else if (OK.equals(reply.result().body().getString(STATUS))) {
response.putHeader(CONTENT_TYPE, APPLICATION_JSON);
response.end(reply.result().body().getString(VALUE));
} else {
response.setStatusCode(StatusCode.NOT_FOUND.getStatusCode());
response.setStatusMessage(StatusCode.NOT_FOUND.getStatusMessage());
response.end(NO_SUCH_LOCK);
}
}));
}
private Optional decodedQueueNameOrRespondWithBadRequest(RoutingContext ctx, String encodedQueueName) {
if (enableQueueNameDecoding) {
String decodedQueueName;
try {
decodedQueueName = java.net.URLDecoder.decode(encodedQueueName, StandardCharsets.UTF_8);
} catch (IllegalArgumentException ex) {
respondWith(StatusCode.BAD_REQUEST, ex.getMessage(), ctx.request());
return Optional.empty();
}
return Optional.of(decodedQueueName);
} else {
return Optional.of(encodedQueueName);
}
}
private void deleteSingleLock(RoutingContext ctx) {
decodedQueueNameOrRespondWithBadRequest(ctx, lastPart(ctx.request().path())).ifPresent(
queue -> eventBus.request(redisquesAddress, buildDeleteLockOperation(queue),
(Handler>>) reply -> {
if (reply.failed()) {
String error = "Received failed message for deleteSingleLockOperation";
log.warn(error, exceptionFactory.newException(reply.cause()));
respondWith(StatusCode.INTERNAL_SERVER_ERROR, error, ctx.request());
} else {
checkReply(reply.result(), ctx.request(), StatusCode.INTERNAL_SERVER_ERROR);
}
}));
}
private void deleteAllLocks(RoutingContext ctx) {
eventBus.request(redisquesAddress, buildDeleteAllLocksOperation(), (Handler>>) reply -> {
if (reply.succeeded() && OK.equals(reply.result().body().getString(STATUS))) {
JsonObject result = new JsonObject();
result.put(DELETED, reply.result().body().getLong(VALUE));
jsonResponse(ctx.response(), result);
} else {
respondWith(StatusCode.INTERNAL_SERVER_ERROR, "Error deleting all locks", ctx.request());
}
});
}
private void bulkPutOrDeleteLocks(RoutingContext ctx) {
ctx.request().bodyHandler(buffer -> {
try {
Result result = extractNonEmptyJsonArrayFromBody(LOCKS, buffer.toString());
if (result.isErr()) {
respondWith(StatusCode.BAD_REQUEST, result.getErr(), ctx.request());
return;
}
if (evaluateUrlParameterToBeEmptyOrTrue(BULK_DELETE_PARAM, ctx.request())) {
bulkDeleteLocks(ctx, result.getOk());
} else {
bulkPutLocks(ctx, result.getOk());
}
} catch (Exception ex) {
respondWith(StatusCode.BAD_REQUEST, ex.getMessage(), ctx.request());
}
});
}
private void bulkDeleteLocks(RoutingContext ctx, JsonArray locks) {
eventBus.request(redisquesAddress, buildBulkDeleteLocksOperation(locks), (Handler>>) reply -> {
if (reply.succeeded() && OK.equals(reply.result().body().getString(STATUS))) {
JsonObject result = new JsonObject();
result.put(DELETED, reply.result().body().getLong(VALUE));
jsonResponse(ctx.response(), result);
} else {
String errorType = reply.result().body().getString(ERROR_TYPE);
if (BAD_INPUT.equalsIgnoreCase(errorType)) {
respondWith(StatusCode.BAD_REQUEST, reply.result().body().getString(MESSAGE), ctx.request());
} else {
respondWith(StatusCode.INTERNAL_SERVER_ERROR, "Error bulk deleting locks", ctx.request());
}
}
});
}
private void bulkPutLocks(RoutingContext ctx, JsonArray locks) {
eventBus.request(redisquesAddress, buildBulkPutLocksOperation(locks, extractUser(ctx.request())),
(Handler>>) reply -> {
if (reply.failed()) {
log.warn("Problem while bulkPutLocks", reply.cause());
// Continue, only to keep backward compatibility.
}
if (reply.succeeded() && OK.equals(reply.result().body().getString(STATUS))) {
respondWith(StatusCode.OK, ctx.request());
} else {
final JsonObject body = reply.result().body();
final String errorType = body.getString(ERROR_TYPE);
if (BAD_INPUT.equalsIgnoreCase(errorType)) {
respondWith(StatusCode.BAD_REQUEST, body.getString(MESSAGE), ctx.request());
} else {
respondWith(StatusCode.INTERNAL_SERVER_ERROR, ctx.request());
}
}
});
}
private void getQueueItemsCount(RoutingContext ctx) {
decodedQueueNameOrRespondWithBadRequest(ctx, lastPart(ctx.request().path())).ifPresent(queue ->
eventBus.request(redisquesAddress, buildGetQueueItemsCountOperation(queue),
(Handler>>) reply -> {
if (reply.failed()) {
log.warn("Failed to getQueueItemsCount", reply.cause());
// Continue, only to keep backward compatibility.
}
if (reply.succeeded() && OK.equals(reply.result().body().getString(STATUS))) {
JsonObject result = new JsonObject();
result.put(COUNT, reply.result().body().getLong(VALUE));
jsonResponse(ctx.response(), result);
} else {
respondWith(StatusCode.INTERNAL_SERVER_ERROR, "Error gathering count of active queue items", ctx.request());
}
})
);
}
private void getConfiguration(RoutingContext ctx) {
eventBus.request(redisquesAddress, buildGetConfigurationOperation(),
(Handler>>) reply -> {
if (reply.failed()) {
log.warn("Failed to getConfiguration.", reply.cause());
// Continue, only to keep backward compatibility.
}
if (reply.succeeded() && OK.equals(reply.result().body().getString(STATUS))) {
jsonResponse(ctx.response(), reply.result().body().getJsonObject(VALUE));
} else {
String error = "Error gathering configuration";
log.error(error);
respondWith(StatusCode.INTERNAL_SERVER_ERROR, error, ctx.request());
}
});
}
private void setConfiguration(RoutingContext ctx) {
ctx.request().bodyHandler((Buffer buffer) -> {
try {
JsonObject configurationValues = new JsonObject(buffer.toString());
eventBus.request(redisquesAddress, buildSetConfigurationOperation(configurationValues),
(Handler>>) reply -> {
if (reply.failed()) {
log.error("Failed to setConfiguration.", reply.cause());
respondWith(StatusCode.INTERNAL_SERVER_ERROR, reply.cause().getMessage(), ctx.request());
} else {
if (OK.equals(reply.result().body().getString(STATUS))) {
respondWith(StatusCode.OK, ctx.request());
} else {
respondWith(StatusCode.BAD_REQUEST, reply.result().body().getString(MESSAGE), ctx.request());
}
}
});
} catch (Exception ex) {
respondWith(StatusCode.BAD_REQUEST, ex.getMessage(), ctx.request());
}
});
}
private void getMonitorInformation(RoutingContext ctx) {
queueStatsService.getQueueStats(ctx, queueStatsMentor);
}
private class MyQueueStatsMentor implements GetQueueStatsMentor {
@Override
public boolean includeEmptyQueues(RoutingContext ctx) {
return evaluateUrlParameterToBeEmptyOrTrue(EMPTY_QUEUES_PARAM, ctx.request());
}
@Override
public int limit(RoutingContext ctx) {
return extractLimit(ctx);
}
@Override
public String filter(RoutingContext ctx) {
return ctx.request().params().get(FILTER);
}
@Override
public void onQueueStatistics(List queues, RoutingContext ctx) {
new Object() {
RoutingContext ctx;
HttpServerResponse rsp;
Iterator queueSrc;
JsonObject queueJson = new JsonObject();
boolean isFirst = true;
void run(RoutingContext ctx_) {
ctx = ctx_;
queueSrc = queues.iterator();
rsp = ctx.request().response();
rsp.putHeader(CONTENT_TYPE, APPLICATION_JSON);
rsp.setChunked(true);
rsp.write("{\"queues\": [");
resumeJsonWriting();
}
void resumeJsonWriting() {
while (true) {
if (rsp.writeQueueFull()) {
// Destination not ready. Apply backpressure, resume when there's space again.
rsp.drainHandler(v -> resumeJsonWriting());
return;
}
if (queueSrc.hasNext()) {
var queue = queueSrc.next();
rsp.write(isFirst ? "" : ",");
isFirst = false;
queueJson.clear();
queueJson.put(MONITOR_QUEUE_NAME, queue.getName());
queueJson.put(MONITOR_QUEUE_SIZE, queue.getSize());
// TODO old impl did bloat result with empty strings for whatever undocumented
// reason. Those fields should be set to 'null' (or we could even skip them
// entirely in JSON), as obviously the information is not available. But
// we'll add the same bloat as we don't know if any downstream code now
// relies on this behavior.
Long epochMs;
epochMs = queue.getLastDequeueAttemptEpochMs();
queueJson.put("lastDequeueAttempt", epochMs == null ? "" : formatAsUIDate(epochMs));
epochMs = queue.getLastDequeueSuccessEpochMs();
queueJson.put("lastDequeueSuccess", epochMs == null ? "" : formatAsUIDate(epochMs));
epochMs = queue.getNextDequeueDueTimestampEpochMs();
queueJson.put("nextDequeueDueTimestamp", epochMs == null ? "" : formatAsUIDate(epochMs));
rsp.write(queueJson.encode());
continue;
}
// All queues written. Time to finalize json.
rsp.end("]}\n");
break;
}
}
}.run(ctx);
}
@Override
public void onError(Throwable ex, RoutingContext ctx) {
if (!ctx.response().headWritten()) {
log.debug("TODO error handling {}", ctx.request().uri(), exceptionFactory.newException(
"Failed to serve queue stats", ex));
StatusCode rspCode = tryExtractStatusCode(ex, StatusCode.INTERNAL_SERVER_ERROR);
respondWith(rspCode, ex.getMessage(), ctx.request());
} else {
log.warn("TODO error handling {}", ctx.request().uri(), exceptionFactory.newException(ex));
}
}
}
private StatusCode tryExtractStatusCode(Throwable ex, StatusCode defaultValue) {
for (Throwable cause = ex.getCause(); cause != null; cause = cause.getCause()) {
if (!(cause instanceof ReplyException)) continue;
ReplyException replyException = (ReplyException) cause;
int errCode = replyException.failureCode();
if (errCode == StatusCode.TOO_MANY_REQUESTS.getStatusCode()) {
return StatusCode.TOO_MANY_REQUESTS;
}
}
return defaultValue;
}
/**
* Old impl did not document WHY this date format got chosen. Now we're
* stuck as consumers likely rely on this format. To get this fixed, we have
* to find and fix all consumers.
*
* @deprecated about date formats
*/
@Deprecated
private String formatAsUIDate(long epochMs) {
return DATE_FORMAT.format(new Date(epochMs));
}
private void listOrCountQueues(RoutingContext ctx) {
if (evaluateUrlParameterToBeEmptyOrTrue(COUNT, ctx.request())) {
getQueuesCount(ctx);
} else {
listQueues(ctx);
}
}
private void getQueuesCount(RoutingContext ctx) {
String filter = ctx.request().params().get(FILTER);
eventBus.request(redisquesAddress, buildGetQueuesCountOperation(filter), (Handler>>) reply -> {
if (reply.failed()) log.warn("TODO error handling", reply.cause());
if (reply.succeeded() && OK.equals(reply.result().body().getString(STATUS))) {
JsonObject result = new JsonObject();
result.put(COUNT, reply.result().body().getLong(VALUE));
jsonResponse(ctx.response(), result);
} else {
String error = "Error gathering count of active queues. Cause: " + reply.result().body().getString(MESSAGE);
String errorType = reply.result().body().getString(ERROR_TYPE);
if (BAD_INPUT.equalsIgnoreCase(errorType)) {
respondWith(StatusCode.BAD_REQUEST, error, ctx.request());
} else {
respondWith(StatusCode.INTERNAL_SERVER_ERROR, "Error gathering count of active queues", ctx.request());
}
}
});
}
private void listQueues(RoutingContext ctx) {
String filter = ctx.request().params().get(FILTER);
eventBus.request(redisquesAddress, buildGetQueuesOperation(filter), (Handler>>) reply -> {
if (reply.failed()) log.warn("TODO error handling", reply.cause());
if (reply.succeeded() && OK.equals(reply.result().body().getString(STATUS))) {
jsonResponse(ctx.response(), reply.result().body().getJsonObject(VALUE));
} else {
String error = "Unable to list active queues. Cause: " + reply.result().body().getString(MESSAGE);
String errorType = reply.result().body().getString(ERROR_TYPE);
if (BAD_INPUT.equalsIgnoreCase(errorType)) {
respondWith(StatusCode.BAD_REQUEST, error, ctx.request());
} else {
respondWith(StatusCode.INTERNAL_SERVER_ERROR, error, ctx.request());
}
}
});
}
private void listOrCountQueueItems(RoutingContext ctx) {
if (evaluateUrlParameterToBeEmptyOrTrue(COUNT, ctx.request())) {
getQueueItemsCount(ctx);
} else {
listQueueItems(ctx);
}
}
private void listQueueItems(RoutingContext ctx) {
decodedQueueNameOrRespondWithBadRequest(ctx, lastPart(ctx.request().path())).ifPresent(queue -> {
String limitParam = null;
if (ctx.request() != null && ctx.request().params().contains(LIMIT)) {
limitParam = ctx.request().params().get(LIMIT);
}
eventBus.request(redisquesAddress, buildGetQueueItemsOperation(queue, limitParam), (Handler>>) reply -> {
if (reply.failed()) {
log.error("Received failed message for listQueueItemsOperation", exceptionFactory.newException(reply.cause()));
respondWith(StatusCode.INTERNAL_SERVER_ERROR, ctx.request());
return;
}
final JsonObject replyBody = reply.result().body();
if (OK.equals(replyBody.getString(STATUS))) {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy