I have a servlet running on Tomcat, and I'm trying to figure out why my output goes like this:
One thread in!
Stops right before API call
successful! Time: 25
AppAsyncListener onComplete
One thread in!
Stops right before API call
AppAsyncListener onTimeout
successful! Time: 204
This should not happen. It blocked my doPost method for 25 seconds before the next thread went in. I read that servlets create a new thread for every doPost, but for some reason here it's being blocked like it's synchronized. Here is my code:
'@WebServlet(name = "League", urlPatterns = { "/League/*" }, asyncSupported = true)
public class BetaServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
ClientConnector connection;
APICaller caller;
/**
* @see HttpServlet#HttpServlet()
*/
public BetaServlet() {
super();
initializeConnectionPool();
caller = new APICaller();
}
private void initializeConnectionPool() {
connection = new ClientConnector("na");// default is North America
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
String reqURL = request.getPathInfo();
if (reqURL != null) {// this means there is an API call using AJAX
System.out.println(reqURL);
switch (reqURL) {
case "/postMatches":
AsyncContext asyncCtx = request.startAsync();
asyncCtx.addListener(new AppAsyncListener());
ThreadPoolExecutor executor = (ThreadPoolExecutor) request.getServletContext().getAttribute("executor");
executor.execute(new AsyncRequestProcessor(asyncCtx, caller, connection));
break;
default:// someone tried to access API that does not exist
response.sendRedirect("/");
break;
}
}
}
I tried to fix it by making it async, but then I realized that the async only works inside of the doPost, which is the bottleneck of the entire operation.
@WebListener
public class AppContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) {
// create the thread pool
ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 200, 50000L,
TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100));
servletContextEvent.getServletContext().setAttribute("executor",
executor);
}
public void contextDestroyed(ServletContextEvent servletContextEvent) {
ThreadPoolExecutor executor = (ThreadPoolExecutor) servletContextEvent
.getServletContext().getAttribute("executor");
executor.shutdown();
}
}
If any other code is needed, please let me know. I'm really confused as to why my doPost is getting jammed when really it was implemented to be multithreaded. Thank you!
EDIT: Code to show where the System.out.println's are.
public class AsyncRequestProcessor implements Runnable {
private AsyncContext asyncContext;
private APICaller caller;
private ClientConnector connection;
private static final boolean KILL_UPON_DUPLICATE = true;
public AsyncRequestProcessor() {
}
public AsyncRequestProcessor(AsyncContext asyncCtx, APICaller caller, ClientConnector connection) {
this.asyncContext = asyncCtx;
this.caller = caller;
this.connection = connection;
}
@Override
public void run() {
System.out.println("Async Supported? "
+ asyncContext.getRequest().isAsyncSupported());
postMatches(asyncContext.getRequest(), asyncContext.getResponse());
//complete the processing
asyncContext.complete();
}
private JSONObject readRequest(ServletRequest request) {
StringBuffer jb = new StringBuffer();
String line = null;
try {
BufferedReader reader = request.getReader();
while ((line = reader.readLine()) != null)
jb.append(line);
} catch (Exception e) {
e.printStackTrace();
}
JSONObject json = null;
try {
json = new JSONObject(jb.toString());
} catch (JSONException e) {
e.printStackTrace();
}
return json;
}
private String generateQueryStringArray(String prefix, String arrayName, JSONObject root) {
try {
JSONArray array = root.getJSONArray(arrayName);
String[] list = new String[array.length()];
for (int i = 0; i < list.length; i++)
list[i] = array.getString(i);
prefix += String.join(",", list);
} catch (Exception e) {
return "";
}
return prefix;
}
private void postMatches(ServletRequest req, ServletResponse res) {
System.out.println("One thread in!");
... other stuff happens ...
}
I am making API calls to RiotGames using Jersey's client framework.