Background Threads Prevent Shutting Down of Basic Scaling Modules

148 views
Skip to first unread message

Tolga Tanrıverdi

unread,
Dec 8, 2016, 3:11:03 AM12/8/16
to Google App Engine
Hi
We're using 5 modules in our Google App Engine application and  all modules uses auto scaling but only 1 of the modules have a background threading function so its using basic scaling with the following configuration:

  <basic-scaling>

    <max-instances>2</max-instances>

    <idle-timeout>2m</idle-timeout>

  </basic-scaling>



As you see instance should be closed in 2 minutes, if it doesnt receive any request. However if we use the below code block it works like 30 minutes without shutting down. When we remove the code its shutting down in 2 minutes as it should be. (This is a test code that we are trying to understand the reason)


  private void doPolling() {

 

   
//Queue notificationQueue = QueueFactory.getQueue("notification-delivery");
   
//PushNotificationWorker worker = new PushNotificationWorker(notificationQueue);

   
while (!LifecycleManager.getInstance().isShuttingDown()) {

     
boolean tasksProcessed = false;  

     
ApiProxy.flushLogs();


 

     
if (!tasksProcessed) {

       
// Wait before trying to lease tasks again.

       
try {

         
Thread.sleep(MILLISECONDS_TO_WAIT_WHEN_NO_TASKS_LEASED);

       
} catch (InterruptedException e) {

         
return;

       
}

     
}

   
}


 

    log
.info("Instance is shutting down");

 
}



Do you know how can we solve that

Jordan (Cloud Platform Support)

unread,
Dec 8, 2016, 4:01:54 PM12/8/16
to Google App Engine
App Engine Basic scaling makes use of Dynamic Instances. Dynamic instances turn off when they are not being used At All. Therefore, since your loop continuously runs, it is forcing your instance to keep alive and never become idle. The only part in your code block that could possibly hit your two minute idle-timeout is your 'Thread.sleep(MILLISECONDS_TO_WAIT_WHEN_NO_TASKS_LEASED);'. 

If you want to properly test your loop, I would recommend performing one of the listed Shutdown Triggers. As noted in the blue box under the 'Shutdown' section, using LifecycleManager is not reliable and you should not base your code on it. There are many reasons why the LifecycleManager wont get a chance to run during instance shutdown, which could cause many problems in your coding logic. 

Tolga Tanrıverdi

unread,
Dec 9, 2016, 4:22:02 AM12/9/16
to Google App Engine
Yes Jordan you're right the part that keeps my instance open is: (I've removed the polling queue code and sleep part ,the instance shutdown successfully)

Thread.sleep(MILLISECONDS_TO_WAIT_WHEN_NO_TASKS_LEASED);

which sleeps the thread for 2.5 seconds if there is nothing in the queue then poll again, and I dont know any other way to keep pooling the pull queues.
You suggested to me to use shutdown triggers, but as far as I know shutdown triggers are for manual scaling. However I dont want to use manual scaling because in that case  I've to calculate when should I shutdown the instance and I also need to decide when to wake the instance. Instead I'm trying to use basic scaling because it automaticly wakes when a new request arrive and also automaticly shutdowns when the idle-timeout time arrives.
Can you suggest me a solution

9 Aralık 2016 Cuma 00:01:54 UTC+3 tarihinde Jordan (Cloud Platform Support) yazdı:

Jordan (Cloud Platform Support)

unread,
Dec 9, 2016, 10:52:45 AM12/9/16
to Google App Engine
The idea of PULL queues is to have a worker always alive to continuously check the PULL queue to see if there are any new tasks for it. This design relies on you always having an instance running your worker's 'while' loop to continuously poll the PULL queue at time intervals. Since you instead want to allow your worker to be shut down to ideally save on instances hours, I would instead suggest you look into PUSH queues

With PUSH queues, your worker instance is only ever awake when there is a new task for it to perform; meaning it gets to shutdown when there is nothing left for it to do, and it never has to poll the queue. This works by creating URL task handlers for your workers. By exposing your worker with a URL endpoint, a PUSH queue only needs to make a request to your worker's URL to wake it up. Your worker then accepts the payload of the HTTP request made to its URL handler, and begins doing its work on that data. Once it is done working, it then becomes idle and can be shutdown by App Engine until a new task is enqueued and the PUSH queue makes a new request to your worker. 



Reply all
Reply to author
Forward
0 new messages