You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Oct 1, 2025. It is now read-only.
Copy file name to clipboardExpand all lines: step5a-gae-ndb-tasks-py2/README.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -24,7 +24,7 @@ Rather than a migration, this step adds use of push Task Queues to the existing
24
24
25
25
1. Add new Python `import`s
26
26
- 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
28
28
1. Save timestamp of last (displayed) `Visit`
29
29
1. Add "delete old(est) entries" task
30
30
1. Display deletion message in web UI template
@@ -88,7 +88,7 @@ def fetch_visits(limit):
88
88
89
89
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.
90
90
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()`.
92
92
93
93
### Add "delete old(est) entries" task
94
94
@@ -117,7 +117,7 @@ Push tasks are `POST`ed to the handler, so that must be specified (default: `GET
117
117
118
118
### Display deletion message in web UI template
119
119
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:
Copy file name to clipboardExpand all lines: step5b-cloud-ndb-tasks-py2/README.md
+30-19Lines changed: 30 additions & 19 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,7 +13,7 @@ In short, these are the Step 5 codelabs/repos:
13
13
- 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 & Cloud Datastore
14
14
15
15
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)])
17
17
- Migrate from App Engine `taskqueue` to Cloud Tasks
18
18
19
19
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
31
31
32
32
### Configuration
33
33
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):
35
35
36
36
Flask==1.1.2
37
37
google-cloud-ndb==1.7.1
@@ -47,7 +47,7 @@ libraries:
47
47
version: 36.6.0
48
48
```
49
49
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:
Our app is currently using the built-in `google.appengine.api.taskqueue` & `google.appengine.ext.ndb` services:
68
+
Our app is currently using the built-in `google.appengine.api.taskqueue` & `google.appengine.ext.ndb` libraries:
69
69
70
70
- BEFORE:
71
71
@@ -78,7 +78,7 @@ from google.appengine.api import taskqueue
78
78
from google.appengine.ext import ndb
79
79
```
80
80
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:
82
82
83
83
84
84
- AFTER:
@@ -92,7 +92,7 @@ from flask import Flask, render_template, request
92
92
from google.cloud import ndb, tasks
93
93
```
94
94
95
-
#### Migrating to Cloud Tasks (and Cloud Datastore)
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.
117
117
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.
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).
132
131
133
132
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).
134
133
@@ -147,14 +146,15 @@ task = {
147
146
```
148
147
149
148
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` & `relative_uri` must be `http_request` & `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` & `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.
156
156
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:
158
158
159
159
- BEFORE:
160
160
@@ -169,7 +169,12 @@ def fetch_visits(limit):
169
169
return (v.to_dict() for v in data), oldest_str
170
170
```
171
171
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:
173
178
174
179
- AFTER:
175
180
@@ -194,6 +199,12 @@ def fetch_visits(limit):
194
199
return (v.to_dict() for v in data), oldest_str
195
200
```
196
201
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
+
197
208
#### Update (Push) Task handler
198
209
199
210
There are very few changes that need to be made to the (push) task handler function.
0 commit comments