Skip to content

Commit

Permalink
new config file option 'maxWorkQueueSize' that lets you set the maxim…
Browse files Browse the repository at this point in the history
…um size of the request queue - if it gets larger than this, requests will be rejected (503 Service unavailable)
  • Loading branch information
danielnaber committed Feb 27, 2015
1 parent c1c0916 commit 793e495
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 3 deletions.
Expand Up @@ -79,6 +79,7 @@ public HTTPSServer(HTTPSServerConfig config, boolean runInternally, String host,
httpHandler.setAfterTheDeadlineMode(config.getAfterTheDeadlineLanguage());
}
httpHandler.setLanguageModel(config.getLanguageModelDir());
httpHandler.setMaxWorkQueueSize(config.getMaxWorkQueueSize());
server.createContext("/", httpHandler);
executorService = getExecutorService(workQueue, config);
server.setExecutor(executorService);
Expand Down
Expand Up @@ -105,6 +105,7 @@ public HTTPServer(HTTPServerConfig config, boolean runInternally, String host, S
httpHandler.setAfterTheDeadlineMode(config.getAfterTheDeadlineLanguage());
}
httpHandler.setLanguageModel(config.getLanguageModelDir());
httpHandler.setMaxWorkQueueSize(config.getMaxWorkQueueSize());
server.createContext("/", httpHandler);
executorService = getExecutorService(workQueue, config);
server.setExecutor(executorService);
Expand Down
Expand Up @@ -52,6 +52,7 @@ enum Mode { LanguageTool, AfterTheDeadline }
protected int requestLimit;
protected int requestLimitPeriodInSeconds;
protected boolean trustXForwardForHeader;
protected int maxWorkQueueSize;

/**
* Create a server configuration for the default port ({@link #DEFAULT_PORT}).
Expand Down Expand Up @@ -114,6 +115,7 @@ private void parseConfigFile(File file) {
requestLimit = Integer.parseInt(getOptionalProperty(props, "requestLimit", "0"));
requestLimitPeriodInSeconds = Integer.parseInt(getOptionalProperty(props, "requestLimitPeriodInSeconds", "0"));
trustXForwardForHeader = Boolean.valueOf(getOptionalProperty(props, "trustXForwardForHeader", "false"));
maxWorkQueueSize = Integer.parseInt(getOptionalProperty(props, "maxWorkQueueSize", "0"));
String langModel = getOptionalProperty(props, "languageModel", null);
if (langModel != null) {
languageModelDir = new File(langModel);
Expand Down Expand Up @@ -239,6 +241,11 @@ boolean getTrustXForwardForHeader() {
return trustXForwardForHeader;
}

/** @since 2.9 */
int getMaxWorkQueueSize() {
return maxWorkQueueSize;
}

/**
* @throws IllegalConfigurationException if property is not set
*/
Expand Down
Expand Up @@ -65,6 +65,7 @@ class LanguageToolHttpHandler implements HttpHandler {
private boolean afterTheDeadlineMode;
private Language afterTheDeadlineLanguage;
private File languageModelDir;
private int maxWorkQueueSize;
private boolean trustXForwardForHeader = false;

/**
Expand Down Expand Up @@ -133,6 +134,17 @@ void setLanguageModel(File languageModelDir) {
this.languageModelDir = languageModelDir;
}

/**
* @param size maximum queue size - if the queue is larger, the user will get an error. Use {@code 0} for no limit.
* @since 2.9
*/
void setMaxWorkQueueSize(int size) {
if (size < 0) {
throw new IllegalArgumentException("Max queue size must be >= 0: " + size);
}
this.maxWorkQueueSize = size;
}

@Override
public void handle(HttpExchange httpExchange) throws IOException {
synchronized (this) {
Expand All @@ -156,6 +168,12 @@ public void handle(HttpExchange httpExchange) throws IOException {
print(errorMessage);
return;
}
if (maxWorkQueueSize != 0 && workQueue.size() > maxWorkQueueSize) {
String response = "Error: There are currently too many parallel requests. Please try again later.";
print(response + " Queue size: " + workQueue.size() + ", maximum size: " + maxWorkQueueSize);
sendError(httpExchange, HttpURLConnection.HTTP_UNAVAILABLE, "Error: " + response);
return;
}
if (allowedIps == null || allowedIps.contains(origAddress)) {
if (requestedUri.getRawPath().endsWith("/Languages")) {
// request type: list known languages
Expand Down Expand Up @@ -259,13 +277,13 @@ private String getLastIpIgnoringOwn(List<String> forwardedIps) {
return lastIp;
}

private void sendError(HttpExchange httpExchange, int returnCode, String response) throws IOException {
private void sendError(HttpExchange httpExchange, int httpReturnCode, String response) throws IOException {
if (afterTheDeadlineMode) {
String xmlResponse = "<results><message>" + escapeForXmlContent(response) + "</message></results>";
httpExchange.sendResponseHeaders(returnCode, xmlResponse.getBytes(ENCODING).length);
httpExchange.sendResponseHeaders(httpReturnCode, xmlResponse.getBytes(ENCODING).length);
httpExchange.getResponseBody().write(xmlResponse.getBytes(ENCODING));
} else {
httpExchange.sendResponseHeaders(returnCode, response.getBytes(ENCODING).length);
httpExchange.sendResponseHeaders(httpReturnCode, response.getBytes(ENCODING).length);
httpExchange.getResponseBody().write(response.getBytes(ENCODING));
}
}
Expand Down
Expand Up @@ -111,6 +111,7 @@ protected static void printCommonConfigFileOptions() {
System.out.println(" 'requestLimitPeriodInSeconds' - time period to which requestLimit applies (optional)");
System.out.println(" 'languageModel' - a directory with a '3grams' sub directory with a Lucene index that");
System.out.println(" contains ngram occurrence counts; activates the confusion rule if supported (optional)");
System.out.println(" 'maxWorkQueueSize' - reject request if request queue gets larger than this (optional)");
}

protected static void printCommonOptions() {
Expand Down
3 changes: 3 additions & 0 deletions languagetool-standalone/CHANGES.txt
Expand Up @@ -71,6 +71,9 @@ LanguageTool Change Log
-Embedded server:
-XML escaping has been fixed, this could cause invalid XML documents
to be returned
-new config file option 'maxWorkQueueSize' that lets you set the maximum
size of the request queue - if it gets larger than this, requests will
be rejected (503 Service unavailable)

-Rule syntax:
-A rule may now have a single example sentence as long as it has a 'correction'
Expand Down

0 comments on commit 793e495

Please sign in to comment.