Using Push Queues in Python
In App Engine push queues, a task is a unit of work to be performed by the application. Each task is an object of the Task class . Each Task object contains an application-specific URL with a request handler for the task, and an optional data payload that parameterizes the task.
For example, consider a calendaring application that needs to notify an invitee, via email, that an event has been updated. The data payload for this task consists of the email address and name of the invitee, along with a description of the event. The webhook might live at
/app_worker/send_email
and contain a function that adds the relevant strings to an email template and sends the email. The app can create a separate task for each email it needs to send.
You can use push queues only within the App Engine environment; if you need to access App Engine tasks from outside of App Engine, use pull queues .
- Using push queues
- Push task execution
- Deferred tasks
- URL endpoints
- Push queues and the development server
- Push queues and backends
- Quotas and limits for push queues
Using push queues
A Python app sets up queues using a configuration file named
queue.yaml
(see
Python Task Queue Configuration
). If an app does not have a
queue.yaml
file, it has a queue named
default
with some default settings.
To enqueue a task, you call the taskqueue.add() function. (You can also create a Task object and call its add() method.) The task consists of data for a request, including a URL path, parameters, HTTP headers, and an HTTP payload. It can also include the earliest time to execute the task (the default is as soon as possible) and a name for the task. The task is added to a queue, then performed by the Task Queue service as the queue is processed.
The following example defines a task handler (
CounterWorker
) that increments a counter in the datastore, mapped to the URL
/worker
. It also defines a user-accessible request handler that displays the current value of the counter for a
GET
request, and for a
POST
request enqueues a task and returns. It's difficult to visualize the execution of tasks with the user-accessible handler if the queue processes them too quickly. Therefore, the task in this example should run at a rate no greater than once per second.
import os
import jinja2
import webapp2
from google.appengine.api import taskqueue
from google.appengine.ext import ndb
JINJA_ENV = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
class Counter(ndb.Model):
count = ndb.IntegerProperty(indexed=False)
class CounterHandler(webapp2.RequestHandler):
def get(self):
template_values = {'counters': Counter.query()}
counter_template = JINJA_ENV.get_template('counter.html')
self.response.out.write(counter_template.render(template_values))
def post(self):
key = self.request.get('key')
# Add the task to the default queue.
taskqueue.add(url='/worker', params={'key': key})
self.redirect('/')
class CounterWorker(webapp2.RequestHandler):
def post(self): # should run at most 1/s due to entity group limit
key = self.request.get('key')
@ndb.transactional
def update_counter():
counter = Counter.get_or_insert(key, count=0)
counter.count += 1
counter.put()
update_counter()
APP = webapp2.WSGIApplication(
[
('/', CounterHandler),
('/worker', CounterWorker)
], debug=True)
(In this example,
'counters.html'
refers to a Jinja2 template that contains the HTML for a page that displays the counter value, and a button to trigger a POST request to the
/
URL.) The full application is available at
our github repository
.
Note that this example is not idempotent. It is possible for the task queue to execute a task more than once. In this case, the counter is incremented each time the task is run, possibly skewing the results.
Push task execution
App Engine executes push tasks by sending HTTP requests to your app. Specifying a programmatic asynchronous callback as an HTTP request is sometimes called a web hook . The web hook model enables efficient parallel processing.
The task's URL determines the handler for the task and the module that runs the handler.
The handler is determined by the path part of the URL (the forward-slash separated string following the hostname), which is specified by using the url parameter of the Task class . The url must be relative and local to your application's root directory. The module (or frontend or backend) and version in which the handler runs is determined by: