Using the task queue, hit app every 10 seconds to keep a hot handler.
### in queue.yaml
queue:
- name: hothandler
rate: 20/m
bucket_size: 1
### in cron.yaml
cron:
- description: ensure hot handler
url: /_ah/queue/hothandler/start
schedule: every 4 hours
### in app.yaml
handlers:
- url: /_ah/queue/hothandler/.*
script: hothandler.py
login: admin
### in hothandler.py
"""
Copyright (C) 2009 twitter.com/rcb
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
"""
import random
from wsgiref.handlers import CGIHandler
from google.appengine.api.labs import taskqueue
from google.appengine.api import memcache
from google.appengine.api.capabilities import CapabilitySet
memcache_service = CapabilitySet('memcache', methods=['set','get'])
hot_handler_queue = taskqueue.Queue(name='hothandler')
HOT_HANDLER_PREFIX = '/_ah/queue/hothandler/'
def wsgi_app(env, res):
""" visit '/_ah/queue/hothandler/start' as admin to start a task """
token = env['PATH_INFO'].replace(HOT_HANDLER_PREFIX,'')
cur_token = memcache.get(HOT_HANDLER_PREFIX)
if cur_token is None:
if not memcache_service.is_enabled():
cur_token = token
if token in [cur_token, 'start']:
next_token = str(random.random())
url = '%s%s'%(HOT_HANDLER_PREFIX, next_token)
next_task = taskqueue.Task(countdown=10, url=url)
hot_handler_queue.add(next_task)
memcache.set(HOT_HANDLER_PREFIX, next_token)
res('200 OK',[('Content-Type','text/plain')])
return ['ok']
def main():
CGIHandler().run(wsgi_app)
if __name__ == '__main__':
main()
### how to launch
1) visit "/_ah/queue/hothandler/start" in your browser
2) login as an admin which inserts the first task
3) view your logs
By the way this is on the production server, the dev server does not
run the tasks automatically.
### view your logs
10-29 10:28PM 11.010 /_ah/queue/hothandler/... 200 17ms 7cpu_ms
10-29 10:28PM 01.018 /_ah/queue/hothandler/... 200 28ms 9cpu_ms
10-29 10:27PM 51.007 /_ah/queue/hothandler/... 200 16ms 5cpu_ms
10-29 10:27PM 41.011 /_ah/queue/hothandler/... 200 18ms 5cpu_ms
10-29 10:27PM 31.007 /_ah/queue/hothandler/... 200 38ms 14cpu_ms
10-29 10:27PM 21.009 /_ah/queue/hothandler/... 200 23ms 7cpu_ms
10-29 10:27PM 11.009 /_ah/queue/hothandler/... 200 20ms 7cpu_ms
10-29 10:27PM 01.009 /_ah/queue/hothandler/... 200 20ms 10cpu_ms
10-29 10:26PM 51.007 /_ah/queue/hothandler/... 200 44ms 35cpu_ms
10-29 10:26PM 41.017 /_ah/queue/hothandler/... 200 24ms 12cpu_ms
Literally like clockwork, a task hits the app once every 10 seconds and keeps it hot.
6 req/minute * 60 minutes/hour * 24 hours/day = 8640 req/day
It is a very small price to pay for good response time with a low volume app.
Memcache is used to ensure there is at most 1 active task, and cron is used
to ensure there is at least 1 active task every 4 hours, so no maintenance.
CapabilitySet is used to test if memcache is available.
Apparently, if 1 handler remains warm, all other warm handlers remain warm too, so
hothandler can exist in its own handler called hothandler.py, which is more modular.