Skip to content

Commit

Permalink
Add startup script; allow gracefull shutdown of server
Browse files Browse the repository at this point in the history
  • Loading branch information
Gabor Angeli authored and Stanford NLP committed Sep 19, 2015
1 parent 4cb7bc4 commit b477bd9
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 19 deletions.
74 changes: 55 additions & 19 deletions src/edu/stanford/nlp/pipeline/StanfordCoreNLPServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import edu.stanford.nlp.util.StringUtils;

import java.io.*;
import java.math.BigInteger;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URLDecoder;
Expand All @@ -27,6 +28,7 @@ public class StanfordCoreNLPServer implements Runnable {
protected HttpServer server;
protected int serverPort;
protected final FileHandler staticPageHandle;
protected final String shutdownKey;

public static int HTTP_OK = 200;
public static int HTTP_BAD_INPUT = 400;
Expand All @@ -42,9 +44,41 @@ public StanfordCoreNLPServer(int port) throws IOException {
defaultProps.setProperty("inputFormat", "text");
defaultProps.setProperty("outputFormat", "json");

// Generate and write a shutdown key
String tmpDir = System.getProperty("java.io.tmpdir");
File tmpFile = new File(tmpDir + File.separator + "corenlp.shutdown");
tmpFile.deleteOnExit();
if (tmpFile.exists()) {
if (!tmpFile.delete()) {
throw new IllegalStateException("Could not delete shutdown key file");
}
}
this.shutdownKey = new BigInteger(130, new Random()).toString(32);
IOUtils.writeStringToFile(shutdownKey, tmpFile.getPath(), "utf-8");

// Set the static page handler
this.staticPageHandle = new FileHandler("edu/stanford/nlp/pipeline/demo/corenlp-brat.html");
}

private static Map<String, String> getURLParams(URI uri) {
if (uri.getQuery() != null) {
Map<String, String> urlParams = new HashMap<>();

String query = uri.getQuery();
String[] queryFields = query.split("&");
for (String queryField : queryFields) {
String[] keyValue = queryField.split("=");
// Convention uses "+" for spaces.
keyValue[0] = keyValue[0].replace("+", " ");
keyValue[1] = keyValue[1].replace("+", " ");
urlParams.put(keyValue[0], keyValue[1]);
}
return urlParams;
} else {
return Collections.emptyMap();
}
}

/**
*
*/
Expand All @@ -60,6 +94,26 @@ public void handle(HttpExchange httpExchange) throws IOException {
}
}

protected class ShutdownHandler implements HttpHandler {
@Override
public void handle(HttpExchange httpExchange) throws IOException {
Map<String, String> urlParams = getURLParams(httpExchange.getRequestURI());
httpExchange.getResponseHeaders().set("Content-Type", "text/plain");
boolean doExit = false;
String response = "Invalid shutdown key\n";
if (urlParams.containsKey("key") && urlParams.get("key").equals(shutdownKey)) {
response = "Shutdown successful!\n";
doExit = true;
}
httpExchange.sendResponseHeaders(HTTP_OK, response.getBytes().length);
httpExchange.getResponseBody().write(response.getBytes());
httpExchange.close();
if (doExit) {
System.exit(0);
}
}
}

/**
* Serve a file from the filesystem or classpath
*/
Expand Down Expand Up @@ -195,25 +249,6 @@ public void handle(HttpExchange httpExchange) throws IOException {
}
}

Map<String, String> getURLParams(URI uri) {
if (uri.getQuery() != null) {
Map<String, String> urlParams = new HashMap<>();

String query = uri.getQuery();
String[] queryFields = query.split("&");
for (String queryField : queryFields) {
String[] keyValue = queryField.split("=");
// Convention uses "+" for spaces.
keyValue[0] = keyValue[0].replace("+", " ");
keyValue[1] = keyValue[1].replace("+", " ");
urlParams.put(keyValue[0], keyValue[1]);
}
return urlParams;
} else {
return Collections.emptyMap();
}
}

private Properties getProperties(HttpExchange httpExchange) throws UnsupportedEncodingException {
// Load the default properties
Properties props = new Properties();
Expand Down Expand Up @@ -260,6 +295,7 @@ public void run() {
server.createContext("/corenlp-brat.js", new FileHandler("edu/stanford/nlp/pipeline/demo/corenlp-brat.js"));
server.createContext("/corenlp-brat.cs", new FileHandler("edu/stanford/nlp/pipeline/demo/corenlp-brat.css"));
server.createContext("/ping", new PingHandler());
server.createContext("/shutdown", new ShutdownHandler());
server.start();
log("StanfordCoreNLPServer listening at " + server.getAddress());
} catch (IOException e) {
Expand Down
58 changes: 58 additions & 0 deletions src/edu/stanford/nlp/pipeline/demo/corenlp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/bin/bash
#
# A script to start/stop the CoreNLP server on port 80, made
# in particular for the configuration running at corenlp.run.
# This script should be placed into:
#
# /etc/init.d/corenlp
#
# To run it at startup, link to the script using:
#
# ln -s /etc/init.d/conenlp /etc/rc.2/S75corenlp
#
# Usage:
#
# service corenlp [start|stop]
# ./corenlp [start|stop]
#

#
# Set this to the username you would like to use to run the server.
# Make sure that this user can authbind to port 80!
#
SERVER_USER="nlp"

do_start()
{
if [ -e '/tmp/corenlp.shutdown' ]; then
echo "CoreNLP server is alredy running!"
echo "If you are sure this is a mistake, delete the file:"
echo "/tmp/corenlp.shutdown"
else
export CLASSPATH=""
for JAR in `find /opt/corenlp -name "*.jar"`; do
CLASSPATH="$CLASSPATH:$JAR"
done
nohup su "$SERVER_USER" -c "/usr/local/bin/authbind --deep java -Djava.net.preferIPv4Stack=true -cp "$CLASSPATH" -mx7g edu.stanford.nlp.pipeline.StanfordCoreNLPServer 80" &
echo "CoreNLP server started."
fi
}

do_stop()
{
if [ ! -e '/tmp/corenlp.shutdown' ]; then
echo "CoreNLP server is not running"
else
KEY=`cat /tmp/corenlp.shutdown`
curl "localhost/shutdown?key=$KEY"
echo "CoreNLP server stopped"
fi
}

case $1 in
start) do_start
;;
stop) do_stop
;;
esac

0 comments on commit b477bd9

Please sign in to comment.