Di chuyển & NDB App Engine Cloud của Python 2 Ứng dụng Cloud Tasks sang Python 3 và Cloud Datastore (Mô-đun 9)

1. Tổng quan

Loạt lớp học lập trình về Trạm di chuyển không máy chủ (hướng dẫn thực hành theo tiến độ riêng) và video có liên quan nhằm giúp các nhà phát triển Google Cloud không máy chủ không hiện đại hoá các ứng dụng của họ bằng cách hướng dẫn họ thực hiện một hoặc nhiều quá trình di chuyển, chủ yếu là ngừng sử dụng các dịch vụ cũ. Việc này giúp ứng dụng của bạn dễ di chuyển hơn, đồng thời mang đến cho bạn nhiều lựa chọn và độ linh hoạt hơn, cho phép bạn tích hợp và truy cập vào nhiều sản phẩm của Cloud hơn, đồng thời dễ dàng nâng cấp lên bản phát hành ngôn ngữ mới hơn. Mặc dù ban đầu tập trung vào những người dùng Cloud sớm nhất, chủ yếu là các nhà phát triển App Engine (môi trường tiêu chuẩn), nhưng loạt bài này đủ rộng để bao gồm các nền tảng không máy chủ khác như Cloud FunctionsCloud Run hoặc ở những nơi khác nếu có.

Mục đích của lớp học lập trình này là chuyển ứng dụng mẫu của Mô-đun 8 sang Python 3 cũng như chuyển quyền truy cập Datastore (Cloud Firestore ở chế độ Datastore) từ việc sử dụng Cloud NDB sang thư viện ứng dụng Cloud Datastore gốc rồi nâng cấp lên phiên bản mới nhất của thư viện ứng dụng Cloud Tasks.

Chúng tôi đã thêm tính năng Hàng đợi tác vụ cho các tác vụ đẩy trong Mô-đun 7, sau đó di chuyển cách sử dụng đó sang Tác vụ trên đám mây trong Mô-đun 8. Ở đây trong Mô-đun 9, chúng ta sẽ tiếp tục với Python 3 và Cloud Datastore. Những người sử dụng Hàng đợi tác vụ để kéo tác vụ sẽ di chuyển sang Cloud Pub/Sub và sẽ tham khảo Mô-đun 18-19.

Bạn sẽ tìm hiểu cách

  • Chuyển ứng dụng mẫu Mô-đun 8 sang Python 3
  • Chuyển quyền truy cập vào Datastore từ Cloud NDB sang thư viện ứng dụng Cloud Datastore
  • Nâng cấp lên phiên bản thư viện ứng dụng Cloud Tasks mới nhất

Bạn cần có

Khảo sát

Bạn sẽ sử dụng hướng dẫn này như thế nào?

Chỉ đọc qua Đọc và hoàn thành bài tập

Bạn đánh giá thế nào về trải nghiệm sử dụng Python?

Người mới tập Trung cấp Thành thạo

Bạn đánh giá thế nào về trải nghiệm sử dụng các dịch vụ của Google Cloud?

Người mới tập Trung cấp Thành thạo

2. Thông tin khái quát

Mô-đun 7 minh hoạ cách sử dụng các tác vụ đẩy hàng đợi tác vụ của App Engine trong các ứng dụng Python 2 Flask App Engine. Trong Mô-đun 8, bạn sẽ di chuyển ứng dụng đó từ Hàng đợi tác vụ sang Cloud Tasks. Ở đây trong Mô-đun 9, bạn sẽ tiếp tục hành trình đó và chuyển ứng dụng đó sang Python 3, cũng như chuyển quyền truy cập Datastore từ việc sử dụng Cloud NDB sang thư viện ứng dụng gốc Cloud Datastore.

Vì Cloud NDB hoạt động cho cả Python 2 và 3, nên nó đủ để người dùng App Engine chuyển ứng dụng của họ từ Python 2 sang 3. Việc di chuyển thêm các thư viện ứng dụng sang Cloud Datastore là hoàn toàn không bắt buộcchỉ có một lý do để cân nhắc việc này: bạn có các ứng dụng không phải App Engine (và/hoặc Python 3 App Engine) đã sử dụng thư viện ứng dụng Cloud Datastore và muốn hợp nhất cơ sở mã để truy cập vào Datastore chỉ bằng một thư viện ứng dụng. Cloud NDB được tạo riêng cho các nhà phát triển Python 2 App Engine dưới dạng công cụ di chuyển Python 3, vì vậy nếu bạn chưa có mã bằng thư viện ứng dụng Cloud Datastore thì bạn không cần xem xét quá trình di chuyển này.

Cuối cùng, thư viện ứng dụng Cloud Tasks chỉ tiếp tục phát triển trong Python 3 nên chúng tôi đang "di chuyển" từ một trong những phiên bản Python 2 cuối cùng đến Python 3 đương đại. May mắn là không có thay đổi nào có thể gây lỗi từ Python 2, có nghĩa là bạn không cần phải làm gì khác ở đây.

Hướng dẫn này bao gồm các bước sau:

  1. Thiết lập/Chuẩn bị
  2. Cập nhật cấu hình
  3. Sửa đổi mã xử lý ứng dụng

3. Thiết lập/Chuẩn bị

Phần này giải thích cách:

  1. Thiết lập dự án trên Cloud
  2. Tải ứng dụng mẫu cơ sở
  3. (Triển khai lại) và xác thực ứng dụng cơ sở

Các bước này giúp đảm bảo bạn đang bắt đầu với đoạn mã đang hoạt động và đoạn mã đó đã sẵn sàng để di chuyển sang các dịch vụ Cloud.

1. Thiết lập dự án

Nếu bạn đã hoàn thành Lớp học lập trình của Mô-đun 8, hãy sử dụng lại chính dự án (và đoạn mã) đó. Ngoài ra, hãy tạo một dự án hoàn toàn mới hoặc sử dụng lại một dự án hiện có khác. Hãy đảm bảo dự án này có một tài khoản thanh toán đang hoạt động và có một ứng dụng App Engine đã bật. Tìm mã dự án của bạn khi cần có sẵn trong lớp học lập trình này, sử dụng mã này bất cứ khi nào bạn gặp biến PROJECT_ID.

2. Tải ứng dụng mẫu cơ sở

Một trong những điều kiện tiên quyết là ứng dụng Mô-đun 8 App Engine đang hoạt động: hoàn thành lớp học lập trình Mô-đun 8 (nên dùng) hoặc sao chép ứng dụng Mô-đun 8 từ kho lưu trữ. Cho dù bạn sử dụng mã của bạn hay mã của chúng tôi, mã Mô-đun 8 là nơi chúng ta sẽ bắt đầu ("BẮT ĐẦU"). Lớp học lập trình này sẽ hướng dẫn bạn thực hiện quá trình di chuyển, kết thúc bằng mã tương tự như những gì trong thư mục kho lưu trữ Mô-đun 9 ("COMPLETED").

Bất kể bạn dùng ứng dụng Mô-đun 7 nào, thư mục đó sẽ có dạng như dưới đây, cũng có thể có cả thư mục lib:

$ ls
README.md               appengine_config.py     requirements.txt
app.yaml                main.py                 templates

3. (Triển khai lại) và xác thực ứng dụng cơ sở

Thực thi các bước sau để triển khai ứng dụng Mô-đun 8:

  1. Xoá thư mục lib (nếu có) rồi chạy pip install -t lib -r requirements.txt để điền lại lib. Bạn có thể cần phải sử dụng pip2 nếu đã cài đặt cả Python 2 và 3 trên máy phát triển.
  2. Hãy đảm bảo bạn đã cài đặtkhởi chạy công cụ dòng lệnh gcloud, đồng thời xem lại việc sử dụng công cụ này.
  3. (không bắt buộc) Thiết lập dự án trên Cloud bằng gcloud config set project PROJECT_ID nếu bạn không muốn nhập PROJECT_ID với mỗi lệnh gcloud bạn đưa ra.
  4. Triển khai ứng dụng mẫu bằng gcloud app deploy
  5. Xác nhận rằng ứng dụng hoạt động như mong đợi mà không gặp vấn đề nào. Nếu bạn đã hoàn thành lớp học lập trình Mô-đun 8, ứng dụng sẽ cho thấy những khách truy cập hàng đầu cùng với những lượt truy cập gần đây nhất (như minh hoạ bên dưới). Ở dưới cùng là thông báo về những việc cần làm cũ sẽ bị xoá.

4aa8a2cb5f527079.pngS

4. Cập nhật cấu hình

requirements.txt

requirements.txt mới gần giống với mô-đun cho Mô-đun 8, chỉ có một thay đổi lớn: thay thế google-cloud-ndb bằng google-cloud-datastore. Thực hiện thay đổi này để tệp requirements.txt của bạn trông giống như sau:

flask
google-cloud-datastore
google-cloud-tasks

Tệp requirements.txt này không có số phiên bản nào, nghĩa là các phiên bản mới nhất đã được chọn. Nếu phát sinh bất kỳ sự không tương thích nào, việc sử dụng số phiên bản để cố định các phiên bản hoạt động của ứng dụng là phương pháp tiêu chuẩn.

app.yaml

Môi trường thời gian chạy App Engine thế hệ thứ hai không hỗ trợ thư viện bên thứ ba tích hợp sẵn như trong 2.x và cũng không hỗ trợ sao chép thư viện không được tích hợp. Yêu cầu duy nhất đối với các gói của bên thứ ba là liệt kê các gói đó trong requirements.txt. Do đó, hệ thống có thể xoá toàn bộ phần libraries của app.yaml.

Một điểm cập nhật khác là môi trường thời gian chạy Python 3 yêu cầu sử dụng các khung web có chức năng định tuyến riêng. Do đó, bạn phải thay đổi tất cả trình xử lý tập lệnh thành auto. Tuy nhiên, vì phải thay đổi tất cả các tuyến thành auto và không có tệp tĩnh nào được phân phát từ ứng dụng mẫu này, nên việc có bất kỳ trình xử lý nào cũng không liên quan, vì vậy, hãy xoá toàn bộ phần handlers.

Điều duy nhất cần thiết trong app.yaml là đặt thời gian chạy thành phiên bản được hỗ trợ của Python 3, giả sử 3.10. Thực hiện thay đổi này sao cho app.yaml mới (được viết tắt) chỉ là một dòng duy nhất sau đây:

runtime: python310

Xoá appengine_config.py và lib

Môi trường thời gian chạy App Engine thế hệ mới cải tiến cách sử dụng gói của bên thứ ba:

  • Thư viện tích hợp là những thư viện đã được Google xem xét kỹ lưỡng và cung cấp trên các máy chủ App Engine, có thể là do các thư viện đó chứa mã C/C++ mà nhà phát triển không được phép triển khai lên đám mây. Các thư viện này không còn được hỗ trợ trong thời gian chạy thế hệ thứ 2 nữa.
  • Bạn không còn cần sao chép thư viện không tích hợp sẵn (đôi khi được gọi là "cung cấp" hoặc "tự gộp nhóm") trong thời gian chạy thế hệ thứ 2 nữa. Thay vào đó, các ứng dụng đó phải được liệt kê trong requirements.txt. Tại đây, hệ thống xây dựng sẽ tự động cài đặt các thành phần này thay cho bạn tại thời điểm triển khai.

Do những thay đổi đó đối với tính năng quản lý gói của bên thứ ba, bạn không cần tệp appengine_config.py và thư mục lib. Vì vậy, hãy xoá chúng. Trong thời gian chạy thế hệ thứ 2, App Engine tự động cài đặt các gói bên thứ ba được liệt kê trong requirements.txt. Tóm tắt:

  1. Không có thư viện bên thứ ba tự nhóm hoặc sao chép; liệt kê chúng trong requirements.txt
  2. Không có pip install trong thư mục lib, nghĩa là không có khoảng thời gian của thư mục lib
  3. Không liệt kê thư viện bên thứ ba tích hợp sẵn (do đó không có phần libraries) trong app.yaml; liệt kê chúng trong requirements.txt
  4. Không có thư viện bên thứ ba để tham chiếu từ ứng dụng của bạn nghĩa là không có tệp appengine_config.py

Việc liệt kê tất cả thư viện của bên thứ ba mong muốn trong requirements.txt là yêu cầu duy nhất của nhà phát triển.

5. Cập nhật tệp ứng dụng

Chỉ có một tệp ứng dụng là main.py, vì vậy, tất cả thay đổi trong phần này chỉ ảnh hưởng đến tệp đó. Dưới đây là một "điểm khác biệt" hình minh hoạ về những thay đổi tổng thể cần được thực hiện để tái cấu trúc mã hiện có thành ứng dụng mới. Độc giả không nên đọc từng dòng mã, vì mục đích của tính năng này chỉ đơn giản là để xem tổng quan bằng hình ảnh về những yêu cầu trong quá trình tái cấu trúc này (nhưng bạn có thể thoải mái mở trong một thẻ mới hoặc tải xuống và phóng to nếu muốn).

5d043768ba7be742.pngS

Cập nhật lệnh nhập và khởi chạy

Phần nhập trong main.py của Mô-đun 8 sử dụng Cloud NDB và Cloud Tasks; đoạn mã sẽ có dạng như sau:

TRƯỚC KHI:

from datetime import datetime
import json
import logging
import time
from flask import Flask, render_template, request
import google.auth
from google.cloud import ndb, tasks

app = Flask(__name__)
ds_client = ndb.Client()
ts_client = tasks.CloudTasksClient()

Việc ghi nhật ký được đơn giản hoá và nâng cao trong thời gian chạy thế hệ thứ hai như Python 3:

  • Để có trải nghiệm ghi nhật ký toàn diện, hãy sử dụng Cloud Logging
  • Để ghi nhật ký đơn giản, bạn chỉ cần gửi đến stdout (hoặc stderr) qua print()
  • Không cần phải sử dụng mô-đun logging Python (vì vậy, hãy xoá mô-đun này)

Do đó, hãy xoá dữ liệu nhập logging và hoán đổi google.cloud.ndb với google.cloud.datastore. Tương tự, hãy thay đổi ds_client để trỏ đến một ứng dụng Datastore thay vì một ứng dụng NDB. Sau khi bạn thực hiện những thay đổi này, phần đầu ứng dụng mới của bạn giờ đây sẽ có dạng như sau:

SAU KHI:

from datetime import datetime
import json
import time
from flask import Flask, render_template, request
import google.auth
from google.cloud import datastore, tasks

app = Flask(__name__)
ds_client = datastore.Client()
ts_client = tasks.CloudTasksClient()

Di chuyển sang Cloud Datastore

Đã đến lúc thay thế việc sử dụng thư viện ứng dụng NDB bằng Datastore. Cả NDB và Cloud NDB của App Engine đều yêu cầu phải có một mô hình dữ liệu (lớp); cho ứng dụng này, đó là Visit. Hàm store_visit() hoạt động như nhau trong tất cả các mô-đun di chuyển khác: đăng ký một lượt truy cập bằng cách tạo một bản ghi Visit mới, lưu địa chỉ IP và tác nhân người dùng (loại trình duyệt) của ứng dụng khách truy cập.

TRƯỚC KHI:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

Tuy nhiên, Cloud Datastore không sử dụng lớp mô hình dữ liệu, vì vậy, hãy xoá lớp đó. Ngoài ra, Cloud Datastore không tự động tạo dấu thời gian khi các bản ghi được tạo và bạn phải làm theo cách thủ công. Việc này được thực hiện thông qua lệnh gọi datetime.now().

Nếu không có lớp dữ liệu, store_visit() được sửa đổi sẽ có dạng như sau:

SAU KHI:

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    entity = datastore.Entity(key=ds_client.key('Visit'))
    entity.update({
        'timestamp': datetime.now(),
        'visitor': '{}: {}'.format(remote_addr, user_agent),
    })
    ds_client.put(entity)

Hàm chính là fetch_visits(). Hàm này không chỉ thực hiện truy vấn ban đầu cho các Visit mới nhất mà còn lấy dấu thời gian của Visit gần nhất được hiển thị rồi tạo tác vụ đẩy gọi /trim (từ đó là trim()) để xoá hàng loạt Visit cũ. Dưới đây là cách sử dụng Cloud NDB:

TRƯỚC KHI:

def fetch_visits(limit):
    'get most recent visits & add task to delete older visits'
    with ds_client.context():
        data = Visit.query().order(-Visit.timestamp).fetch(limit)
    oldest = time.mktime(data[-1].timestamp.timetuple())
    oldest_str = time.ctime(oldest)
    logging.info('Delete entities older than %s' % oldest_str)
    task = {
        'app_engine_http_request': {
            'relative_uri': '/trim',
            'body': json.dumps({'oldest': oldest}).encode(),
            'headers': {
                'Content-Type': 'application/json',
            },
        }
    }
    ts_client.create_task(parent=QUEUE_PATH, task=task)
    return (v.to_dict() for v in data), oldest_str

Những thay đổi chính:

  1. Hoán đổi truy vấn Cloud NDB cho Cloud Datastore tương đương; kiểu truy vấn sẽ hơi khác nhau.
  2. Datastore không yêu cầu sử dụng trình quản lý ngữ cảnh và cũng không bắt bạn trích xuất dữ liệu (bằng to_dict()) như Cloud NDB.
  3. Thay thế các lệnh gọi ghi nhật ký bằng print()

Sau những thay đổi đó, fetch_visits() sẽ có dạng như sau:

SAU KHI:

def fetch_visits(limit):
    'get most recent visits & add task to delete older visits'
    query = ds_client.query(kind='Visit')
    query.order = ['-timestamp']
    visits = list(query.fetch(limit=limit))
    oldest = time.mktime(visits[-1]['timestamp'].timetuple())
    oldest_str = time.ctime(oldest)
    print('Delete entities older than %s' % oldest_str)
    task = {
        'app_engine_http_request': {
            'relative_uri': '/trim',
            'body': json.dumps({'oldest': oldest}).encode(),
            'headers': {
                'Content-Type': 'application/json',
            },
        }
    }
    ts_client.create_task(parent=QUEUE_PATH, task=task)
    return visits, oldest_str

Thông thường, đây là tất cả những gì cần thiết. Rất tiếc, có một vấn đề lớn.

(Có thể) Tạo hàng đợi (đẩy) mới

Trong Mô-đun 7, chúng ta đã thêm việc sử dụng taskqueue của App Engine vào ứng dụng hiện có của Mô-đun 1. Một lợi ích chính của việc sử dụng các tác vụ đẩy như một tính năng cũ của App Engine là "mặc định" hàng đợi được tạo tự động. Khi ứng dụng đó được chuyển sang Cloud Tasks trong Mô-đun 8, hàng đợi mặc định đó đã có sẵn, vì vậy chúng ta vẫn không cần phải lo lắng về việc này. Điều đó được thay đổi ở đây trong Mô-đun 9.

Một khía cạnh quan trọng cần lưu ý là ứng dụng App Engine mới không còn sử dụng các dịch vụ của App Engine nữa. Do đó, bạn không còn có thể cho rằng App Engine tự động tạo hàng đợi công việc trong một sản phẩm khác (Cloud Tasks) nữa. Như đã viết, bạn sẽ không thể tạo một tác vụ trong fetch_visits() (đối với một hàng đợi không tồn tại). Bạn cần có một hàm mới để kiểm tra xem hàng đợi ("default") có tồn tại hay không. Nếu không có, hãy tạo một hàm mới.

Gọi hàm này là _create_queue_if() rồi thêm vào ứng dụng của bạn ngay phía trên fetch_visits() vì đó là nơi hàm này được gọi. Phần nội dung của hàm cần thêm:

def _create_queue_if():
    'app-internal function creating default queue if it does not exist'
    try:
        ts_client.get_queue(name=QUEUE_PATH)
    except Exception as e:
        if 'does not exist' in str(e):
            ts_client.create_queue(parent=PATH_PREFIX,
                    queue={'name': QUEUE_PATH})
    return True

Hàm create_queue() của Cloud Tasks yêu cầu tên đường dẫn đầy đủ của hàng đợi ngoại trừ tên hàng đợi. Để đơn giản hoá, hãy tạo một biến khác PATH_PREFIX đại diện cho QUEUE_PATH trừ đi tên hàng đợi (QUEUE_PATH.rsplit('/', 2)[0]). Thêm định nghĩa của khối này ở gần phía trên cùng để khối mã có tất cả các phép gán không đổi trông giống như sau:

_, PROJECT_ID = google.auth.default()
REGION_ID = 'REGION_ID'    # replace w/your own
QUEUE_NAME = 'default'     # replace w/your own
QUEUE_PATH = ts_client.queue_path(PROJECT_ID, REGION_ID, QUEUE_NAME)
PATH_PREFIX = QUEUE_PATH.rsplit('/', 2)[0]

Bây giờ, hãy sửa đổi dòng cuối cùng trong fetch_visits() để sử dụng _create_queue_if(), trước tiên là tạo hàng đợi nếu cần, rồi tạo tác vụ sau:

    if _create_queue_if():
        ts_client.create_task(parent=QUEUE_PATH, task=task)
    return visits, oldest_str

Bây giờ, cả _create_queue_if()fetch_visits() sẽ có dạng như sau:

def _create_queue_if():
    'app-internal function creating default queue if it does not exist'
    try:
        ts_client.get_queue(name=QUEUE_PATH)
    except Exception as e:
        if 'does not exist' in str(e):
            ts_client.create_queue(parent=PATH_PREFIX,
                    queue={'name': QUEUE_PATH})
    return True

def fetch_visits(limit):
    'get most recent visits & add task to delete older visits'
    query = ds_client.query(kind='Visit')
    query.order = ['-timestamp']
    visits = list(query.fetch(limit=limit))
    oldest = time.mktime(visits[-1]['timestamp'].timetuple())
    oldest_str = time.ctime(oldest)
    print('Delete entities older than %s' % oldest_str)
    task = {
        'app_engine_http_request': {
            'relative_uri': '/trim',
            'body': json.dumps({'oldest': oldest}).encode(),
            'headers': {
                'Content-Type': 'application/json',
            },
        }
    }
    if _create_queue_if():
        ts_client.create_task(parent=QUEUE_PATH, task=task)
    return visits, oldest_str

Ngoại trừ việc phải thêm mã bổ sung này, phần còn lại của mã Cloud Tasks gần như không thay đổi trong Mô-đun 8. Phần mã cuối cùng cần xem xét là trình xử lý tác vụ.

Cập nhật trình xử lý tác vụ (đẩy)

Trong trình xử lý tác vụ trim(), các truy vấn mã Cloud NDB cho các lượt truy cập cũ hơn lượt truy cập cũ nhất được hiển thị. Công cụ này sử dụng truy vấn chỉ có khoá để đẩy nhanh tiến độ. Tại sao lại tìm nạp tất cả dữ liệu nếu bạn chỉ cần Mã truy cập? Sau khi bạn có tất cả mã truy cập, hãy xoá tất cả cùng một lúc bằng hàm delete_multi() của Cloud NDB.

TRƯỚC KHI:

@app.route('/trim', methods=['POST'])
def trim():
    '(push) task queue handler to delete oldest visits'
    oldest = float(request.get_json().get('oldest'))
    with ds_client.context():
        keys = Visit.query(
                Visit.timestamp < datetime.fromtimestamp(oldest)
        ).fetch(keys_only=True)
        nkeys = len(keys)
        if nkeys:
            logging.info('Deleting %d entities: %s' % (
                    nkeys, ', '.join(str(k.id()) for k in keys)))
            ndb.delete_multi(keys)
        else:
            logging.info(
                    'No entities older than: %s' % time.ctime(oldest))
    return ''   # need to return SOME string w/200

Giống như fetch_visits(), phần lớn thay đổi liên quan đến việc hoán đổi mã Cloud NDB cho Cloud Datastore, tinh chỉnh kiểu truy vấn, ngừng sử dụng trình quản lý ngữ cảnh và thay đổi lệnh gọi ghi nhật ký thành print().

SAU KHI:

@app.route('/trim', methods=['POST'])
def trim():
    '(push) task queue handler to delete oldest visits'
    oldest = float(request.get_json().get('oldest'))
    query = ds_client.query(kind='Visit')
    query.add_filter('timestamp', '<', datetime.fromtimestamp(oldest))
    query.keys_only()
    keys = list(visit.key for visit in query.fetch())
    nkeys = len(keys)
    if nkeys:
        print('Deleting %d entities: %s' % (
                nkeys, ', '.join(str(k.id) for k in keys)))
        ds_client.delete_multi(keys)
    else:
        print('No entities older than: %s' % time.ctime(oldest))
    return ''   # need to return SOME string w/200

Không có thay đổi nào đối với trình xử lý ứng dụng chính root().

Chuyển sang Python 3

Ứng dụng mẫu này được thiết kế để chạy trên cả Python 2 và 3. Mọi thay đổi cụ thể đối với Python 3 đều được đề cập trước đó trong các phần liên quan của hướng dẫn này. Bạn không cần thực hiện bước bổ sung hay thư viện tương thích.

Thông tin cập nhật về Cloud Tasks

Phiên bản cuối cùng của thư viện ứng dụng Cloud Tasks hỗ trợ Python 2 là 1.5.0. Tại thời điểm viết bài này, phiên bản mới nhất của thư viện ứng dụng cho Python 3 hoàn toàn tương thích với phiên bản đó, do đó bạn không cần cập nhật gì thêm.

Cập nhật mẫu HTML

Bạn cũng không cần thay đổi gì trong tệp mẫu HTML templates/index.html. Vì vậy, thao tác này sẽ kết thúc tất cả các thay đổi cần thiết để chuyển đến ứng dụng Mô-đun 9.

6. Tóm tắt/Dọn dẹp

Triển khai và xác minh ứng dụng

Sau khi bạn hoàn tất việc cập nhật mã, chủ yếu là cổng đến Python 3, hãy triển khai ứng dụng bằng gcloud app deploy. Kết quả sẽ giống với các ứng dụng từ ứng dụng Mô-đun 7 và 8 ngoại trừ việc bạn đã chuyển quyền truy cập cơ sở dữ liệu vào thư viện ứng dụng Cloud Datastore và đã nâng cấp lên Python 3:

Ứng dụng visitme mô-đun 7

Bước này hoàn tất lớp học lập trình. Chúng tôi mời bạn so sánh mã của bạn với nội dung trong thư mục Mô-đun 9. Xin chúc mừng!

Dọn dẹp

Giải pháp chung

Nếu bạn đã hoàn tất, chúng tôi khuyên bạn nên tắt ứng dụng App Engine để tránh phát sinh thanh toán. Tuy nhiên, nếu bạn muốn kiểm tra hoặc thử nghiệm thêm, nền tảng App Engine có hạn mức miễn phí, và bạn sẽ không bị tính phí, miễn là bạn không vượt quá cấp sử dụng đó. Đó là cho dịch vụ điện toán nhưng bạn cũng có thể bị tính phí cho các dịch vụ có liên quan của App Engine, vì vậy hãy xem trang giá của dịch vụ này để biết thêm thông tin. Nếu quá trình di chuyển này liên quan đến các dịch vụ khác trên Google Cloud, thì những dịch vụ đó sẽ được tính phí riêng. Trong cả hai trường hợp (nếu có), hãy xem phần "Dành riêng cho lớp học lập trình này" phần dưới đây.

Để công bố đầy đủ thông tin, việc triển khai cho một nền tảng điện toán không máy chủ của Google Cloud như App Engine sẽ làm phát sinh chi phí bản dựng và bộ nhớ thấp. Cloud Build cũng có hạn mức miễn phí riêng, tương tự như Cloud Storage. Việc lưu trữ hình ảnh đó sẽ sử dụng hết một phần hạn mức đó. Tuy nhiên, bạn có thể sống ở một khu vực không có bậc miễn phí như vậy, vì vậy hãy chú ý đến mức sử dụng bộ nhớ của bạn để giảm thiểu chi phí tiềm ẩn. "Thư mục" cụ thể trên Cloud Storage bạn nên xem xét, bao gồm:

  • console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
  • console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
  • Các đường liên kết lưu trữ ở trên phụ thuộc vào PROJECT_ID và hoạt động *LOC*của bạn, ví dụ: "us" nếu ứng dụng của bạn được lưu trữ ở Hoa Kỳ.

Mặt khác, nếu bạn không định tiếp tục sử dụng ứng dụng này hoặc các lớp học lập trình di chuyển khác có liên quan và muốn xoá hoàn toàn mọi thứ, hãy ngừng dự án của bạn.

Dành riêng cho lớp học lập trình này

Các dịch vụ được liệt kê dưới đây là những dịch vụ dành riêng cho lớp học lập trình này. Hãy tham khảo tài liệu của từng sản phẩm để biết thêm thông tin:

Các bước tiếp theo

Đến đây, chúng tôi đã hoàn tất quá trình di chuyển từ Hàng đợi tác vụ của App Engine sang các tác vụ trên Cloud Tasks. Quá trình di chuyển không bắt buộc từ Cloud NDB sang Cloud Datastore cũng sẽ tự đề cập (không có Hàng đợi tác vụ hoặc Cloud Tasks) trong Mô-đun 3. Ngoài Mô-đun 3, bạn cũng cần cân nhắc sử dụng các mô-đun di chuyển khác tập trung vào việc ngừng sử dụng các dịch vụ đi kèm cũ của App Engine:

  • Mô-đun 2: di chuyển từ App Engine NDB sang Cloud NDB
  • Mô-đun 3: di chuyển từ Cloud NDB sang Cloud Datastore
  • Mô-đun 12-13: di chuyển từ App Engine Memcache sang Cloud Memorystore
  • Mô-đun 15-16: di chuyển từ App Engine Blobstore sang Cloud Storage
  • Mô-đun 18-19: Hàng đợi tác vụ của App Engine (lấy tác vụ) lên Cloud Pub/Sub

App Engine không còn là nền tảng không máy chủ duy nhất trên Google Cloud nữa. Nếu bạn có một ứng dụng App Engine nhỏ hoặc một ứng dụng có chức năng hạn chế và muốn biến ứng dụng đó thành một dịch vụ vi mô độc lập, hoặc bạn muốn chia một ứng dụng nguyên khối thành nhiều thành phần có thể sử dụng lại, thì đây là những lý do chính đáng để bạn cân nhắc chuyển sang Cloud Functions. Nếu việc tích hợp vùng chứa đã trở thành một phần trong quy trình phát triển ứng dụng, đặc biệt là khi quy trình đó bao gồm một quy trình CI/CD (tích hợp liên tục/phân phối hoặc triển khai liên tục), hãy cân nhắc chuyển sang Cloud Run. Những trường hợp này được đề cập trong các mô-đun sau:

  • Di chuyển từ App Engine sang Cloud Functions: xem Học phần 11
  • Di chuyển từ App Engine sang Cloud Run: xem Mô-đun 4 để vùng chứa ứng dụng của bạn bằng Docker, hoặc Mô-đun 5 để triển khai mà không cần vùng chứa, kiến thức về Docker hoặc Dockerfile

Việc chuyển sang một nền tảng không máy chủ khác là không bắt buộc. Bạn nên cân nhắc các lựa chọn phù hợp nhất cho ứng dụng và trường hợp sử dụng của mình trước khi điều chỉnh bất cứ điều gì.

Bất kể bạn cân nhắc mô-đun di chuyển nào tiếp theo, bạn đều có thể truy cập vào tất cả nội dung của Trạm di chuyển không máy chủ (lớp học lập trình, video, mã nguồn [nếu có]) tại kho lưu trữ nguồn mở của chúng. README của kho lưu trữ này cũng cung cấp hướng dẫn về những quá trình di chuyển cần xem xét và mọi "đơn đặt hàng" có liên quan Mô-đun di chuyển.

7. Tài nguyên khác

Vấn đề/ý kiến phản hồi về lớp học lập trình

Nếu bạn gặp vấn đề với lớp học lập trình này, vui lòng tìm vấn đề của bạn trước khi gửi. Đường liên kết để tìm kiếm và báo cáo vấn đề mới:

Tài nguyên di chuyển

Bạn có thể tìm thấy các đường liên kết đến các thư mục repo cho Mô-đun 8 (START) và Mô-đun 9 (Finish) trong bảng bên dưới. Bạn cũng có thể truy cập vào các tệp này qua kho lưu trữ dành cho mọi quá trình di chuyển trong lớp học lập trình App Engine. Tại đây, bạn có thể sao chép hoặc tải tệp ZIP xuống.

Codelab

Python 2

Python 3

Học phần 8

(không áp dụng)

Mô-đun 9

(không áp dụng)

Tài nguyên trực tuyến

Dưới đây là các tài nguyên trực tuyến có thể phù hợp với hướng dẫn này:

App Engine

Cloud NDB

Lưu trữ dữ liệu trên đám mây

Cloud Tasks

Thông tin khác về đám mây

Giấy phép

Tác phẩm này được cấp phép theo Giấy phép chung Ghi nhận tác giả Creative Commons 2.0.