Cách sử dụng Hàng đợi công việc của App Engine (công việc đẩy) trong ứng dụng Flask (Mô-đun 7)

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ó.

Lớp học lập trình này hướng dẫn bạn cách sử dụng tác vụ đẩy hàng đợi tác vụ của App Engine trong ứng dụng mẫu từ Lớp học lập trình Mô-đun 1. Bài đăng trên blog và video của Mô-đun 7 bổ sung cho hướng dẫn này, cung cấp thông tin tổng quan ngắn gọn về nội dung trong hướng dẫn này.

Trong mô-đun này, chúng ta sẽ thêm tính năng sử dụng tác vụ đẩy, sau đó di chuyển hoạt động sử dụng đó sang Cloud Tasks trong Mô-đun 8 trở lên sang Python 3 và Cloud Datastore trong Mô-đun 9. 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

  • Sử dụng API/dịch vụ theo gói/API hàng đợi tác vụ của App Engine
  • Thêm cách sử dụng tác vụ đẩy vào ứng dụng NDB cơ bản của Python 2 Flask App Engine

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ó thể đọc Đọ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

Hàng đợi tác vụ của App Engine hỗ trợ cả tác vụ đẩy và kéo. Để cải thiện khả năng có thể di chuyển của ứng dụng, nhóm Google Cloud đề xuất di chuyển từ các dịch vụ đi kèm cũ (như Hàng đợi tác vụ) sang các dịch vụ độc lập khác của Google Cloud hoặc các dịch vụ tương đương của bên thứ ba.

Việc di chuyển tác vụ kéo được đề cập trong Mô-đun di chuyển 18-19 trong khi Mô-đun 7-9 tập trung vào di chuyển tác vụ đẩy. Để di chuyển khỏi các tác vụ đẩy trong Hàng đợi tác vụ của App Engine, hãy thêm cách sử dụng của tác vụ đó vào ứng dụng NDB của Flask và App Engine hiện có từ Lớp học lập trình dành cho Mô-đun 1. Trong ứng dụng đó, lượt xem trang mới đăng ký Lượt truy cập mới và hiển thị lượt truy cập gần đây nhất cho người dùng. Vì các lượt truy cập cũ hơn không bao giờ được hiển thị lại và chiếm dung lượng trong Datastore, chúng ta sẽ tạo một tác vụ đẩy để tự động xoá các lượt truy cập cũ nhất. Trong phần trước trong Mô-đun 8, chúng tôi sẽ di chuyển ứng dụng đó từ Hàng đợi tác vụ sang Cloud Tasks.

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.

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

Nếu đã hoàn thành Lớp học lập trình về Mô-đun 1, bạn nên sử dụng lại chính dự án (và mã nguồn). Ngoài ra, bạn có thể 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. Đảm bảo dự án này có một tài khoản thanh toán đang hoạt động và đã bật App Engine.

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

Một trong những điều kiện tiên quyết của lớp học lập trình này là phải có ứng dụng App Engine của Mô-đun 1 hoạt động: hoàn thành Lớp học lập trình Mô-đun 1 (nên có) hoặc sao chép Ứng dụng Mô-đun 1 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 1 là nơi chúng tôi sẽ "BẮT ĐẦU". Lớp học lập trình này sẽ hướng dẫn bạn qua từng bước, kết thúc bằng mã tương tự như những gì trong thư mục repo của Mô-đun 7 "Finish".

Bất kể bạn dùng ứng dụng Mô-đun 1 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               main.py                 templates
app.yaml                requirements.txt

3. (Triển khai lại) ứng dụng cơ sở

Thực thi các bước sau để triển khai (lại) ứng dụng Mô-đun 1:

  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. Thay vào đó, bạn có thể cần phải sử dụng lệnh pip2 nếu đã cài đặt cả Python 2 và 3.
  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 xét cách sử dụng công cụ này.
  3. 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 cho mỗi lệnh gcloud được đư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 Mô-đun 1 chạy như dự kiến mà không gặp vấn đề khi hiển thị những lượt truy cập gần đây nhất (hình minh hoạ bên dưới)

a7a9d2b80d706a2b.png

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

Không cần thay đổi gì đối với các tệp cấu hình App Engine chuẩn (app.yaml, requirements.txt, appengine_config.py).

5. Sửa đổi tệp ứng dụng

Tệp đăng ký chính là main.py và tất cả nội dung cập nhật trong phần này đều liên quan đến tệp đó. Ngoài ra, chúng tôi cũng có một bản cập nhật nhỏ cho mẫu web templates/index.html. Sau đây là những thay đổi cần triển khai trong phần này:

  1. Cập nhật lệnh nhập
  2. Thêm tác vụ đẩy
  3. Thêm trình xử lý công việc
  4. Cập nhật mẫu web

1. Cập nhật lệnh nhập

Việc nhập google.appengine.api.taskqueue mang đến chức năng Hàng đợi tác vụ. Bạn cũng cần có một số gói thư viện chuẩn Python:

  • Vì chúng ta đang thêm một nhiệm vụ để xoá các lượt truy cập cũ nhất, nên ứng dụng sẽ cần xử lý dấu thời gian, nghĩa là sử dụng timedatetime.
  • Để ghi lại thông tin hữu ích về quá trình thực thi tác vụ, chúng ta cần có logging.

Sau khi thêm tất cả các lệnh nhập này, mã của bạn sẽ trông như thế nào trước và sau những thay đổi này:

TRƯỚC KHI:

from flask import Flask, render_template, request
from google.appengine.ext import ndb

SAU KHI:

from datetime import datetime
import logging
import time
from flask import Flask, render_template, request
from google.appengine.api import taskqueue
from google.appengine.ext import ndb

2. Thêm công việc đẩy (đối chiếu dữ liệu cho công việc, thêm công việc mới vào hàng đợi)

Tài liệu về hàng đợi đẩy nêu rõ: "Để xử lý một nhiệm vụ, bạn phải thêm nhiệm vụ đó vào hàng đợi đẩy. App Engine cung cấp một hàng đợi đẩy mặc định, có tên là default. Hàng đợi này đã được định cấu hình và sẵn sàng để sử dụng với các chế độ cài đặt mặc định. Nếu muốn, bạn có thể chỉ cần thêm tất cả việc cần làm của mình vào hàng đợi mặc định mà không phải tạo và định cấu hình các hàng đợi khác". Lớp học lập trình này sử dụng hàng đợi default để trình bày ngắn gọn. Để tìm hiểu thêm về cách xác định hàng đợi đẩy của riêng bạn, với các đặc điểm giống nhau hoặc khác nhau, vui lòng xem tài liệu về Cách tạo hàng đợi đẩy.

Mục tiêu chính của lớp học lập trình này là thêm một tác vụ (vào hàng đợi đẩy default) có nhiệm vụ là xoá các lượt truy cập cũ không còn hiển thị khỏi Datastore. Ứng dụng cơ sở đăng ký mỗi lượt truy cập (yêu cầu GET đến /) bằng cách tạo một thực thể Visit mới, sau đó tìm nạp và hiển thị những lượt truy cập gần đây nhất. Hệ thống sẽ không hiển thị hoặc sử dụng lại lượt truy cập cũ nhất nào, vì vậy, tác vụ đẩy sẽ xoá tất cả lượt truy cập cũ hơn lần truy cập cũ nhất được hiển thị. Để thực hiện việc này, hành vi của ứng dụng cần thay đổi một chút:

  1. Khi truy vấn các lượt truy cập gần đây nhất, thay vì ngay lập tức trả về các lượt truy cập đó, hãy sửa đổi ứng dụng để lưu dấu thời gian của Visit lượt truy cập cũ nhất (cũ nhất). Bạn có thể xoá tất cả các lượt truy cập cũ hơn thời gian này.
  2. Tạo một tác vụ đẩy có dấu thời gian này là tải trọng và hướng tác vụ đó đến trình xử lý tác vụ, có thể truy cập qua giao thức HTTP POST đến /trim. Cụ thể, hãy sử dụng các tiện ích Python tiêu chuẩn để chuyển đổi dấu thời gian Datastore và gửi (dưới dạng số thực có độ chính xác đơn) đến tác vụ, nhưng đồng thời ghi nhật ký (dưới dạng chuỗi) và trả về chuỗi đó dưới dạng giá trị trọng điểm để hiển thị cho người dùng.

Toàn bộ quá trình này đều diễn ra trong fetch_visits() và trước và sau khi cập nhật:

TRƯỚC KHI:

def fetch_visits(limit):
    return (v.to_dict() for v in Visit.query().order(
            -Visit.timestamp).fetch(limit))

SAU KHI:

def fetch_visits(limit):
    'get most recent visits and add task to delete older visits'
    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)
    taskqueue.add(url='/trim', params={'oldest': oldest})
    return (v.to_dict() for v in data), oldest_str

3. Thêm trình xử lý tác vụ (mã được gọi khi tác vụ chạy)

Mặc dù việc xoá lượt truy cập cũ có thể dễ dàng được thực hiện trong fetch_visits(), nhưng xin lưu ý rằng chức năng này không liên quan nhiều đến người dùng cuối. Đó là chức năng phụ trợ và là một lựa chọn phù hợp để xử lý không đồng bộ bên ngoài các yêu cầu ứng dụng thông thường. Người dùng cuối sẽ hưởng lợi từ việc truy vấn nhanh hơn vì sẽ có ít thông tin hơn trong Datastore. Tạo một hàm mới trim(), được gọi qua yêu cầu Hàng đợi tác vụ POST tới /trim. Hàm này sẽ thực hiện những việc sau:

  1. Trích xuất "lượt ghé thăm cũ nhất" tải trọng dấu thời gian
  2. Đưa ra truy vấn Datastore để tìm tất cả các thực thể cũ hơn dấu thời gian đó.
  3. Chọn sử dụng chế độ "chỉ sử dụng khoá" nhanh hơn vì không cần dữ liệu người dùng thực tế.
  4. Ghi nhật ký số lượng thực thể cần xoá (kể cả 0).
  5. Gọi ndb.delete_multi() để xoá mọi thực thể (sẽ bỏ qua nếu không thực hiện).
  6. Trả về một chuỗi trống (cùng với mã trả về HTTP 200 ngầm ẩn).

Bạn có thể xem tất cả thông tin đó trong trim() bên dưới. Thêm vào main.py ngay sau fetch_visits():

@app.route('/trim', methods=['POST'])
def trim():
    '(push) task queue handler to delete oldest visits'
    oldest = request.form.get('oldest', type=float)
    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

4. Cập nhật mẫu web

Cập nhật mẫu web templates/index.html, với Jinja2 có điều kiện này để hiển thị dấu thời gian cũ nhất nếu biến đó tồn tại:

{% if oldest is defined %}
    <b>Deleting visits older than:</b> {{ oldest }}</p>
{% endif %}

Thêm đoạn mã này sau danh sách lượt truy cập được hiển thị, nhưng trước khi đóng phần nội dung để mẫu của bạn trông giống như sau:

<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<body>

<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
    <li>{{ visit.timestamp.ctime() }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>

{% if oldest is defined %}
    <b>Deleting visits older than:</b> {{ oldest }}</p>
{% endif %}
</body>
</html>

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

Phần này tóm tắt lớp học lập trình này bằng cách triển khai ứng dụng, xác minh rằng ứng dụng hoạt động như dự kiến và trong mọi đầu ra được phản ánh. Sau khi xác thực ứng dụng, hãy dọn dẹp và cân nhắc các bước tiếp theo.

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

Triển khai ứng dụng bằng gcloud app deploy. Kết quả phải giống với ứng dụng Mô-đun 1, ngoại trừ một dòng mới ở dưới cùng cho biết những lượt truy cập nào sẽ bị xoá:

4aa8a2cb5f527079.pngS

Chúc mừng bạn đã hoàn thành lớp học lập trình. Mã của bạn bây giờ sẽ khớp với nội dung trong thư mục kho lưu trữ Mô-đun 7. Hiện đã sẵn sàng để di chuyển sang Cloud Tasks trong Mô-đun 8.

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

Trong quá trình "di chuyển" này, bạn đã thêm việc sử dụng hàng đợi đẩy hàng đợi tác vụ vào ứng dụng mẫu Mô-đun 1, thêm tính năng hỗ trợ theo dõi khách truy cập, dẫn đến ứng dụng mẫu Mô-đun 7. Lần di chuyển tiếp theo sẽ hướng dẫn bạn cách nâng cấp từ App Engine đẩy tác vụ lên Cloud Tasks nếu bạn chọn làm như vậy. Kể từ mùa thu năm 2021, người dùng không còn phải chuyển sang Cloud Tasks khi nâng cấp lên Python 3. Đọc thêm về điều này trong phần tiếp theo.

Nếu bạn muốn chuyển sang Cloud Tasks, thì tiếp theo là Lớp học lập trình cho Mô-đun 8. Ngoài ra, bạn có thể cân nhắc các quá trình di chuyển khác, chẳng hạn như Cloud Datastore, Cloud Memorystore, Cloud Storage hoặc Cloud Pub/Sub (hàng đợi kéo). Ngoài ra, chúng tôi cũng sẽ di chuyển giữa nhiều sản phẩm sang Cloud Run và Cloud Functions. Bạn có thể truy cập 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 nó.

7. Di chuyển sang Python 3

Mùa thu năm 2021, nhóm App Engine mở rộng khả năng hỗ trợ nhiều dịch vụ đi kèm sang môi trường thời gian chạy thế hệ 2 (ban đầu chỉ có trong môi trường thời gian chạy thế hệ 1). Điều này có nghĩa là bạn không còn phải di chuyển từ các dịch vụ đi kèm (như Hàng đợi tác vụ của App Engine sang Hàng đợi tác vụ của App Engine) sang Đám mây độc lập hoặc các dịch vụ tương đương của bên thứ ba như Cloud Tasks khi chuyển ứng dụng sang Python 3. Nói cách khác, bạn có thể tiếp tục sử dụng Hàng đợi tác vụ trong các ứng dụng App Engine Python 3 miễn là bạn điều chỉnh mã để truy cập các dịch vụ đi kèm từ thời gian chạy thế hệ tiếp theo.

Bạn có thể tìm hiểu thêm về cách di chuyển hoạt động sử dụng các dịch vụ theo gói sang Python 3 trong Lớp học lập trình về Mô-đun 17 và video tương ứng. Mặc dù chủ đề đó nằm ngoài phạm vi của Mô-đun 7, nhưng được liên kết bên dưới là các phiên bản Python 3 của cả hai ứng dụng Mô-đun 1 và 7 được chuyển sang Python 3 và vẫn sử dụng NDB và Hàng đợi tác vụ của App Engine.

8. Tài nguyên khác

Dưới đây là các tài nguyên bổ sung dành cho nhà phát triển đang tìm hiểu thêm về Phụ lục di chuyển này hoặc mô-đun di chuyển có liên quan cũng như các sản phẩm có liên quan. Trong đó có cả những nơi để đưa ra ý kiến phản hồi về nội dung này, các đường liên kết đến mã nguồn và nhiều thông tin hữu ích khác của tài liệu.

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

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 2 (START) và Mô-đun 7 (Finish) trong bảng bên dưới.

Codelab

Python 2

Python 3

Học phần 1

(không có trong hướng dẫn này)

Học phần 7 (lớp học lập trình này)

(không có trong hướng dẫn này)

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:

Hàng đợi tác vụ của App Engine

Nền tảng App Engine

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

Video

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.