Skip to content
This repository was archived by the owner on Oct 1, 2025. It is now read-only.

Commit a11ecbc

Browse files
committed
minor cleanup of task queue stuff
1 parent 9587f95 commit a11ecbc

File tree

4 files changed

+37
-24
lines changed

4 files changed

+37
-24
lines changed

step5a-gae-ndb-tasks-py2/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Rather than a migration, this step adds use of push Task Queues to the existing
2424

2525
1. Add new Python `import`s
2626
- Add use of Python standard library date and time utilities
27-
- (optional but helpful) Add logging and function ["docstrings"](http://python.org/dev/peps/pep-0257/#id15)
27+
- (optional but helpful) Add logging
2828
1. Save timestamp of last (displayed) `Visit`
2929
1. Add "delete old(est) entries" task
3030
1. Display deletion message in web UI template
@@ -88,7 +88,7 @@ def fetch_visits(limit):
8888

8989
The `data` variable holds the `Visit`s previously returned immediately, and `oldest` is the timestamp of the oldest displayed `Visit` in seconds (as a `float`) since the epoch, retrieved by (extracting `datetime` object, morphed to Python [time 9-tuple normalized form](https://docs.python.org/library/time), then converted to `float`). A string version is also created for display purposes. A new push task is added, calling the handler (`/trim`) with `oldest` as its only parameter.
9090

91-
The same payload as the Step 1 `fetch_visits()` is returned to the caller in addition to `oldest` as a string. Following good practices, a function docstring was added (first unassigned string) along with an application log at the `INFO` level via `logging.info()`.
91+
The same payload as the Step 1 `fetch_visits()` is returned to the caller in addition to `oldest` as a string. Following good practices, add an application log at the `INFO` level via `logging.info()`.
9292

9393
### Add "delete old(est) entries" task
9494

@@ -117,7 +117,7 @@ Push tasks are `POST`ed to the handler, so that must be specified (default: `GET
117117

118118
### Display deletion message in web UI template
119119

120-
It's also a good practice to have "docstrings" to document functionality, so add those as well. Add the following snippet after the unnumbered list of `Visit`s but before the closing `</body>` tag:
120+
Add the following snippet after the unnumbered list of `Visit`s but before the closing `</body>` tag:
121121

122122
```html+jinja
123123
{% if oldest %}

step5a-gae-ndb-tasks-py2/main.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ def trim():
5151
nkeys, ', '.join(str(k.id()) for k in keys)))
5252
ndb.delete_multi(keys)
5353
else:
54-
logging.info('No entities older than: %s' % time.ctime(oldest))
54+
logging.info(
55+
'No entities older than: %s' % time.ctime(oldest))
5556
return '' # need to return SOME string w/200
5657

5758
@app.route('/')

step5b-cloud-ndb-tasks-py2/README.md

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ In short, these are the Step 5 codelabs/repos:
1313
- Step 5c ([codelab](https://codelabs.developers.google.com/codelabs/cloud-gae-python-migrate-5c-cloudtasksds.md), [repo](/step5c-cloud-ndb-tasks-py3)): Migrate Step 5b app to second-generation Python 3 App Engine &amp; Cloud Datastore
1414

1515
In *this* codelab/repo, participants start with the code in the (completed) [Step 5a repo](https://github.com/googlecodelabs/migrate-python-appengine-datastore/tree/master/step5a-gae-ndb-tasks-py2). That repo resulted from taking the [Step 1 sample app](https://github.com/googlecodelabs/migrate-python-appengine-datastore/tree/master/step1-flask-gaendb-py2) and adding push tasks to it using the App Engine `taskqueue` API library. This tutorial performs a pair of migrations from *that* starting point:
16-
- Migrate from App Engine `ndb` to Cloud NDB (same as [Step 2 codelab](https://codelabs.developers.google.com/codelabs/cloud-gae-python-migrate-2-cloudndb))
16+
- Migrate from App Engine `ndb` to Cloud NDB (same as Step 2 [[codelab](https://codelabs.developers.google.com/codelabs/cloud-gae-python-migrate-2-cloudndb), [repo](https://github.com/googlecodelabs/migrate-python-appengine-datastore/tree/master/step2-flask-cloudndb-py2)])
1717
- Migrate from App Engine `taskqueue` to Cloud Tasks
1818

1919
If you haven't completed the [Step 5a codelab](https://codelabs.developers.google.com/codelabs/cloud-gae-python-migrate-5-gaetasks), we recommend you do so to familiarize yourself with its codebase as we start from there. (You can also just study the code in its repo linked above.)
@@ -31,7 +31,7 @@ The migration from App Engine `ndb` to Cloud NDB is identical to that of Step 2
3131

3232
### Configuration
3333

34-
The `requirements.txt` from Step 5a only listed Flask as a required package. In this step, add the client libraries for Cloud NDB and Clodu Tasks so the updated `requirements.txt` looks like this:
34+
The `requirements.txt` from Step 5a listed only Flask as a required package. Cloud NDB and Cloud Tasks have their own client libraries, so in this step, add their packages to `requirements.txt` so it looks like this (but choose the most recent versions as these were the latest at the time of this writing):
3535

3636
Flask==1.1.2
3737
google-cloud-ndb==1.7.1
@@ -47,7 +47,7 @@ libraries:
4747
version: 36.6.0
4848
```
4949
50-
Update `appengine_config.py` to use `pkg_resources` to tie those built-in libraries to the bundled/vendored third-party libraries like Flask:
50+
Update `appengine_config.py` to use `pkg_resources` to tie those built-in libraries to the bundled/vendored third-party libraries like Flask and the Google Cloud client libraries:
5151

5252
```python
5353
import pkg_resources
@@ -65,7 +65,7 @@ pkg_resources.working_set.add_entry(PATH)
6565

6666
#### Imports
6767

68-
Our app is currently using the built-in `google.appengine.api.taskqueue` &amp; `google.appengine.ext.ndb` services:
68+
Our app is currently using the built-in `google.appengine.api.taskqueue` &amp; `google.appengine.ext.ndb` libraries:
6969

7070
- BEFORE:
7171

@@ -78,7 +78,7 @@ from google.appengine.api import taskqueue
7878
from google.appengine.ext import ndb
7979
```
8080

81-
Replace both those imports with `google.cloud.ndb` and `google.cloud.tasks`. Furthermore, Cloud Tasks requires you to JSON-encode the task's payload, so also import `json`. When you're done, here's what the `import` section of `main.py` should look like:
81+
Replace both with `google.cloud.ndb` and `google.cloud.tasks`. Furthermore, Cloud Tasks requires you to JSON-encode the task's payload, so also import `json`. When you're done, here's what the `import` section of `main.py` should look like:
8282

8383

8484
- AFTER:
@@ -92,7 +92,7 @@ from flask import Flask, render_template, request
9292
from google.cloud import ndb, tasks
9393
```
9494

95-
#### Migrating to Cloud Tasks (and Cloud Datastore)
95+
#### Migrate to Cloud Tasks (and Cloud NDB)
9696

9797
- BEFORE:
9898

@@ -113,22 +113,21 @@ def store_visit(remote_addr, user_agent):
113113
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
114114
```
115115

116-
The more significant update affects `fetch_visits()`, primarily involving the switch from App Engine push task queues to Cloud Tasks, a standalone Google Cloud product with its own client library (added to `requirements.txt`). Along with `with` statement wrappers around Datastore access, creating a task is no longer a 1-liner.
116+
Cloud Tasks currently requires an App Engine be enabled for your Google Cloud project in order for you to use it (even if you don't have any App Engine code), otherwise tasks queues will not function. (See [this section](https://cloud.google.com/tasks/docs/creating-queues#before_you_begin) in the docs for more information.) Cloud Tasks supports tasks running on App Engine (App Engine "targets") but can also be run on any HTTP endpoint (HTTP targets) with a public IP address, such as Cloud Functions, Cloud Run, GKE, Compute Engine, or even an on-prem web server. Our simple app uses an App Engine target for tasks.
117117

118-
First, Tasks are an independent service, so in addition to a separate client library, you need to tell Google Cloud where to run your tasks. At the top of `main.py` under Flask initialization, developers must initialize both Cloud NDB and Cloud Tasks, along with some constants that determine your Tasks' "path":
118+
Some setup is needed to use Cloud NDB and Cloud Tasks. At the top of `main.py` under Flask initialization, initialize Cloud NDB and Cloud Tasks. Also define some constants that indicate where your push tasks will execute.
119119

120120
```python
121121
app = Flask(__name__)
122122
ds_client = ndb.Client()
123-
<b>ts_client = tasks.CloudTasksClient()</b>
123+
ts_client = tasks.CloudTasksClient()
124124
125125
PROJECT_ID = 'PROJECT_ID' # replace w/your own
126126
REGION_ID = 'REGION_ID' # replace w/your own
127127
QUEUE_NAME = 'default' # replace w/your own
128128
QUEUE_PATH = ts_client.queue_path(PROJECT_ID, REGION_ID, QUEUE_NAME)
129129
```
130-
131-
Obviously once you've created your Tasks queue, fill-in your project's `PROJECT_ID`, the `REGION_ID` in which your Tasks will run (should be the same as your App Engine region), and the name of your push queue. App Engine features a "`default`" queue, so we'll use that name (but you don't have to).
130+
Obviously once you've [created your task queue](https://cloud.google.com/tasks/docs/creating-queues), fill-in your project's `PROJECT_ID`, the `REGION_ID` where your tasks will run (should be the same as your App Engine region), and the name of your push queue. App Engine features a "`default`" queue, so we'll use that name (but you don't have to).
132131

133132
The `default` queue is special and created automatically under certain circumstances, one of which is when using *App Engine APIs*, so if you (re)use the same project as Step 5a, `default` will already exist. However if you created a *new* project specifically for Step 5b, you'll need to create `default` manually. More info on the `default` queue can be found on [this page](https://cloud.google.com/tasks/docs/queue-yaml#cloud_tasks_and_the_default_app_engine_queue).
134133

@@ -147,14 +146,15 @@ task = {
147146
```
148147

149148
What are you looking at above?
150-
1. Tasks are no longer tied to App Engine; they can now execute on Cloud Functions, "DIY", etc.
151-
1. If App Engine is hosting the task, then specify `app_engine_http_request` as the request type and `relative_uri` points to the App Engine task handler.
152-
1. If App Engine is *not* hosting the task, then `app_engine_http_request` &amp; `relative_uri` must be `http_request` &amp; `url`, respectively, instead.
153-
1. `body`: the JSON- and Unicode string-encoded parameters to send to the (push) task
154-
1. Since parameters are JSON-encoded, need to specify its `Content-Type` header explicity
155-
1. Refer to the [documentation](https://cloud.google.com/tasks/docs/reference/rpc/google.cloud.tasks.v2#task) for more info.
149+
1. Supply task target information:
150+
- For App Engine targets, specify `app_engine_http_request` as the request type and `relative_uri` is the App Engine task handler.
151+
- For HTTP targets, use `http_request` &amp; `url` instead.
152+
1. `body`: the JSON- and Unicode string-encoded parameter(s) to send to the (push) task
153+
1. Specify a JSON-encoded `Content-Type` header explicity
154+
155+
Refer to the [documentation](https://cloud.google.com/tasks/docs/reference/rpc/google.cloud.tasks.v2#task) for more info on your options here.
156156

157-
This is `fetch_visits()` from the last tutorial:
157+
With setup out of the way, let's update `fetch_visits()`. Here is what it looks like from the previous tutorial:
158158

159159
- BEFORE:
160160

@@ -169,7 +169,12 @@ def fetch_visits(limit):
169169
return (v.to_dict() for v in data), oldest_str
170170
```
171171

172-
Once you have the queue's full path and payload ready to go, a call to `ts_client.create_task()` will do the job. Wrapping the query in a context manager, here is what your updated `fetch_visits()` should look like:
172+
The required updates:
173+
1. Switch from App Engine `ndb` to Cloud NDB
174+
1. New code to extract timestamp of oldest visit displayed
175+
1. Use Cloud Tasks to create a new task instead of App Engine `taskqueue`
176+
177+
Here's what your new `fetch_visits()` should look like:
173178

174179
- AFTER:
175180

@@ -194,6 +199,12 @@ def fetch_visits(limit):
194199
return (v.to_dict() for v in data), oldest_str
195200
```
196201

202+
Summarizing the code update:
203+
- Switch to Cloud NDB means moving Datastore code inside a `with` statement
204+
- Switch to Cloud Tasks means using `ts_client.create_task()` instead of `taskqueue.add()`
205+
- Pass in the queue's full path and `task` payload (described earlier)
206+
207+
197208
#### Update (Push) Task handler
198209

199210
There are very few changes that need to be made to the (push) task handler function.

step5b-cloud-ndb-tasks-py2/main.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ def trim():
7070
nkeys, ', '.join(str(k.id()) for k in keys)))
7171
ndb.delete_multi(keys)
7272
else:
73-
logging.info('No entities older than: %s' % time.ctime(oldest))
73+
logging.info(
74+
'No entities older than: %s' % time.ctime(oldest))
7475
return '' # need to return SOME string w/200
7576

7677
@app.route('/')

0 commit comments

Comments
 (0)