java - Google App Engine Modules + HttpServlet with static values; -
i developing application delivers notifications android , ios devices. using basic scaling , have implemented logic (modifying example) appropriate number of workers active @ given time without using resident instance.
public class notificationworkerservlet extends httpservlet { /** * */ private static final long serialversionuid = 1l; private static final logger log = logger .getlogger(notificationworkerservlet.class.getname()); private static final int max_worker_count = 5; private static final int milliseconds_to_wait_when_no_tasks_leased = 2500; private static final int ten_minutes = (10 * 60 * 1000); // area of concern private static synccounter counter; /** * used keep number of running workers in sync */ private class synccounter { private int c = 0; public synccounter(){ log.info("sync counter instantiated"); } public synchronized void increment() { c++; log.info("increment sync counter, workers:" + c); } public synchronized void decrement() { c--; log.info("decrement sync counter, workers:" + c); } public synchronized int value() { return c; } } /** * call made module when notification added task queue */ @override protected void dopost(httpservletrequest req, httpservletresponse resp) throws servletexception, ioexception { super.dopost(req, resp); // instantiate counter first call if(counter == null){ counter = new synccounter(); } log.info("starting build workers"); (int workerno = counter.value(); workerno < max_worker_count; workerno++) { log.info("starting thread worker: " + workerno); // current queue check it's statistics queue notificationqueue = queuefactory .getqueue("notification-delivery"); if (notificationqueue.fetchstatistics().getnumtasks() > 30 * workerno) { counter.increment(); thread thread = threadmanager .createbackgroundthread(new runnable() { @override public void run() { try { dopolling(); } catch (exception e) { e.printstacktrace(); } } }); thread.start(); } else { break; // current number of threads sufficient. } } resp.setstatus(httpservletresponse.sc_ok); } /** * poll task queue , lease tasks * * wait 10 minutes tasks added queue before killing * tasks * */ private void dopolling() { log.info("doing pulling"); try { int loopswithoutprocessedtasks = 0; queue notificationqueue = queuefactory .getqueue("notification-delivery"); notificationworker worker = new notificationworker( notificationqueue); while (!lifecyclemanager.getinstance().isshuttingdown()) { boolean tasksprocessed = worker.processbatchoftasks(); apiproxy.flushlogs(); if (!tasksprocessed) { log.info("waiting tasks"); // wait before trying lease tasks again. try { loopswithoutprocessedtasks++; // if worker hasn't had tasks 30 min, kill it. if (loopswithoutprocessedtasks >= (ten_minutes / milliseconds_to_wait_when_no_tasks_leased)) { break; } else { // else, wait , try again (to avoid tearing down // useful notification senders) thread.sleep(milliseconds_to_wait_when_no_tasks_leased); } } catch (interruptedexception e) { log.info("notification worker thread interrupted"); break; } } else { log.info("processed batch of tasks"); loopswithoutprocessedtasks = 0; } } } catch (exception e) { log.warning("exception caught , handled in notification worker: " + e.getlocalizedmessage()); } { counter.decrement(); } log.info("instance shutting down"); }
}
in controlled testing scenario, works fine. however, know static, mutable values bad news in servlets multiple users potentially connecting @ same time.
has done similar , had issues pushing multiple notifications same device, lost tasks or had idle tasks burning hole in bank?
Comments
Post a Comment