Skip to content

Commit 718417d

Browse files
committed
App Engine Task Queue example using pull queues.
Copied from: https://github.com/GoogleCloudPlatform/appengine-pullqueue-counter and tests added.
1 parent 507a179 commit 718417d

File tree

8 files changed

+169
-0
lines changed

8 files changed

+169
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# App Engine Task Queue Pull Counter
2+
3+
<!-- auto-doc-link -->
4+
These samples are used on the following documentation page:
5+
6+
> https://cloud.google.com/appengine/docs/python/taskqueue/overview-pull
7+
8+
<!-- end-auto-doc-link -->
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
runtime: python27
2+
api_version: 1
3+
threadsafe: true
4+
5+
handlers:
6+
- url: /.*
7+
script: main.app
8+
9+
libraries:
10+
- name: jinja2
11+
version: 2.6
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<body>
4+
<form action="/" method="POST">
5+
<label for="key">Key:</label><input type="text" name="key" id="key">
6+
<input type="submit" value="+1">
7+
</form>
8+
<ul>
9+
{% for counter in counters %}
10+
<li>
11+
{{counter.key.id()|e}}: {{counter.count|e}}
12+
</li>
13+
{% endfor %}
14+
</body>
15+
</html>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# [START all]
16+
"""A simple counter with App Engine pull queue."""
17+
18+
import logging
19+
import os
20+
import time
21+
22+
from google.appengine.api import taskqueue
23+
from google.appengine.ext import ndb
24+
from google.appengine.runtime import apiproxy_errors
25+
import jinja2
26+
import webapp2
27+
28+
29+
JINJA_ENV = jinja2.Environment(
30+
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
31+
32+
33+
class Counter(ndb.Model):
34+
count = ndb.IntegerProperty(indexed=False)
35+
36+
37+
class CounterHandler(webapp2.RequestHandler):
38+
def get(self):
39+
template_values = {'counters': Counter.query()}
40+
counter_template = JINJA_ENV.get_template('counter.html')
41+
self.response.out.write(counter_template.render(template_values))
42+
43+
def post(self):
44+
key = self.request.get('key')
45+
if key:
46+
queue = taskqueue.Queue('pullq')
47+
queue.add(taskqueue.Task(payload='', method='PULL', tag=key))
48+
self.redirect('/')
49+
50+
51+
class CounterWorker(webapp2.RequestHandler):
52+
def get(self):
53+
"""Indefinitely fetch tasks and update the datastore."""
54+
queue = taskqueue.Queue('pullq')
55+
while True:
56+
try:
57+
tasks = queue.lease_tasks_by_tag(3600, 1000, deadline=60)
58+
except (taskqueue.TransientError,
59+
apiproxy_errors.DeadlineExceededError) as e:
60+
logging.exception(e)
61+
time.sleep(1)
62+
continue
63+
if tasks:
64+
key = tasks[0].tag
65+
66+
@ndb.transactional
67+
def update_counter():
68+
counter = Counter.get_or_insert(key, count=0)
69+
counter.count += len(tasks)
70+
counter.put()
71+
try:
72+
update_counter()
73+
except Exception as e:
74+
logging.exception(e)
75+
else:
76+
queue.delete_tasks(tasks)
77+
time.sleep(1)
78+
79+
80+
app = webapp2.WSGIApplication([
81+
('/', CounterHandler),
82+
('/_ah/start', CounterWorker)
83+
], debug=True)
84+
# [END all]
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import os
16+
17+
from google.appengine.ext import testbed as gaetestbed
18+
import main
19+
import webtest
20+
21+
22+
def test_app(testbed):
23+
key_name = 'foo'
24+
25+
testbed.init_taskqueue_stub(root_path=os.path.dirname(__file__))
26+
27+
app = webtest.TestApp(main.app)
28+
app.post('/', {'key': key_name})
29+
30+
tq_stub = testbed.get_stub(gaetestbed.TASKQUEUE_SERVICE_NAME)
31+
tasks = tq_stub.get_filtered_tasks()
32+
assert len(tasks) == 1
33+
assert tasks[0].name == 'task1'
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
queue:
2+
- name: pullq
3+
mode: pull
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module: worker
2+
api_version: 1
3+
runtime: python27
4+
instance_class: B1
5+
threadsafe: yes
6+
manual_scaling:
7+
instances: 1
8+
9+
handlers:
10+
- url: /.*
11+
script: main.app
12+
13+
libraries:
14+
- name: jinja2
15+
version: 2.6

0 commit comments

Comments
 (0)