Modul 8: Melakukan migrasi dari App Engine ndb dan taskqueue ke Cloud NDB dan Cloud Tasks

Rangkaian codelab ini (tutorial praktik mandiri) bertujuan untuk membantu developer Google App Engine (Standar) memodernisasi aplikasi mereka dengan memandu mereka melalui serangkaian migrasi. Langkah yang paling signifikan adalah beralih dari layanan paket runtime asli karena runtime generasi berikutnya lebih fleksibel, sehingga memberikan opsi layanan yang lebih beragam kepada pengguna. Peralihan ke runtime generasi baru memungkinkan Anda berintegrasi dengan produk Google Cloud dengan lebih mudah, menggunakan berbagai layanan yang didukung, dan mendukung rilis bahasa saat ini.

Codelab ini membantu pengguna melakukan migrasi dari tugas push App Engine dan taskqueue API/library-nya ke Cloud Tasks. Jika aplikasi Anda tidak menggunakan Task Queues, Anda dapat menggunakan codelab ini sebagai latihan untuk mempelajari cara memigrasikan tugas push App Engine ke Cloud Tasks.

Anda akan mempelajari cara

  • Melakukan migrasi dari App Engine taskqueue ke Cloud Tasks
  • Membuat tugas push dengan Cloud Tasks
  • Melakukan migrasi dari App Engine ndb ke Cloud NDB (sama dengan Modul 2)

Yang akan Anda perlukan

Survei

Bagaimana Anda akan menggunakan codelab ini?

Hanya membacanya Membacanya dan menyelesaikan latihan

Karena kami menambahkan tugas push App Engine ke aplikasi sampel di codelab (Module 7) sebelumnya, sekarang kita dapat memigrasikannya ke Cloud Tasks. Migrasi dalam tutorial ini memaparkan langkah-langkah utama berikut:

  1. Penyiapan/Prakerja
  2. Memperbarui file konfigurasi
  3. Memperbarui aplikasi utama

Sebelum memulai bagian utama tutorial, mari kita siapkan project, dapatkan kodenya, lalu deploy aplikasi dasar pengukuran sehingga kita tahu bahwa kita memulai dengan kode yang berfungsi.

1. Siapkan project

Sebaiknya gunakan kembali project yang sama dengan yang Anda gunakan untuk menyelesaikan codelab Modul 7. Atau, Anda dapat membuat project baru atau menggunakan kembali project lain yang sudah ada. Pastikan project memiliki akun penagihan yang aktif dan App Engine (aplikasi) diaktifkan.

2. Dapatkan aplikasi contoh dasar pengukuran

Salah satu prasyarat untuk codelab ini adalah memiliki aplikasi contoh Modul 7 yang berfungsi. Jika Anda tidak memilikinya, sebaiknya selesaikan tutorial Modul 7 (link di atas) sebelum melanjutkan ke sini. Jika sudah terbiasa dengan kontennya, Anda bisa memulai dengan mengambil kode Modul 7 di bawah.

Baik Anda menggunakan kode Anda atau kode kami, kode Modul 7 adalah tempat kita akan memulai (START). Codelab Modul 2 ini akan memandu Anda melalui setiap langkah, dan setelah selesai, kode akan menyerupai kode pada titik FINISH (termasuk port opsional dari Python 2 hingga 3).

Direktori file Modul 7 (milik Anda atau milik kami) akan terlihat seperti ini:

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

Jika sudah menyelesaikan tutorial Modul 7, Anda juga akan memiliki folder lib dengan Flask dan dependensinya.

3. Deploy (ulang) aplikasi Modul 7

Langkah prakerja yang tersisa untuk dijalankan sekarang:

  1. Biasakan kembali diri Anda dengan alat command-line gcloud (jika perlu)
  2. Deploy (ulang) kode Modul 7 ke App Engine (jika perlu)

Setelah Anda berhasil menjalankan langkah-langkah tersebut dan mengonfirmasikan operasinya, kita akan melanjutkan tutorial ini, dimulai dengan file konfigurasi.

requirements.txt

requirements.txt dari Modul 7 hanya mencantumkan Flask sebagai paket wajib. Cloud NDB dan Cloud Tasks memiliki library klien sendiri, jadi di langkah ini, tambahkan paket tersebut ke requirements.txt agar terlihat seperti ini:

Flask==1.1.2
google-cloud-ndb==1.7.1
google-cloud-tasks==1.5.0

Sebaiknya gunakan versi terbaru dari setiap library; nomor versi di atas adalah yang terbaru untuk Python 2 pada saat penulisan tutorial ini. (Paket setara Python 3 kemungkinan akan berada pada versi yang lebih tinggi.) Kode dalam folder repo FINISH lebih sering diperbarui dan mungkin memiliki rilis baru, meskipun kecil kemungkinan untuk library Python 2 yang biasanya dibekukan.

app.yaml

Lihat library bawaan grpcio dan setuptools di app.yaml pada bagian libraries:

libraries:
- name: grpcio
  version: 1.0.0
- name: setuptools
  version: 36.6.0

appengine_config.py

Perbarui appengine_config.py untuk menggunakan pkg_resources guna mengikat library bawaan tersebut ke library pihak ke-3 yang disalin seperti Flask dan library klien Google Cloud:

import pkg_resources
from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
# Add libraries to pkg_resources working set to find the distribution.
pkg_resources.working_set.add_entry(PATH)

Hanya ada satu file aplikasi, main.py, sehingga semua perubahan di bagian ini hanya memengaruhi file tersebut.

Perbarui impor dan inisialisasi

Aplikasi kami saat ini menggunakan library google.appengine.api.taskqueue dan google.appengine.ext.ndb bawaan:

  • SEBELUM:
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

Ganti keduanya dengan google.cloud.ndb dan google.cloud.tasks. Selain itu, Cloud Tasks mengharuskan Anda melakukan enkode JSON terhadap payload tugas, sehingga juga mengimpor json. Setelah selesai, berikut ini tampilan bagian import dari main.py:

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

Lakukan Migrasi ke Cloud Tasks (dan Cloud NDB)

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

Tidak ada perubahan pada store_visit() selain yang Anda lakukan di Modul 2: tambahkan pengelola konteks ke semua akses Datastore. Hal ini disediakan dalam bentuk pemindahan pembuatan Entitas Visit baru yang digabungkan di pernyataan with.

  • SETELAH:
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()

Cloud Tasks saat ini mengharuskan App Engine diaktifkan untuk project Google Cloud agar Anda dapat menggunakannya (meskipun Anda tidak memiliki kode App Engine), jika tidak, task queue tidak akan berfungsi. (Lihat bagian ini di dokumen untuk informasi selengkapnya.) Cloud Tasks mendukung tugas yang berjalan di App Engine ("target" App Engine), tetapi juga dapat dijalankan di endpoint HTTP (target HTTP) dengan alamat IP publik, seperti Cloud Functions, Cloud Run, GKE, Compute Engine, atau bahkan server web lokal. Aplikasi sederhana kami menggunakan target App Engine untuk tugas.

Beberapa penyiapan diperlukan untuk menggunakan Cloud NDB dan Cloud Tasks. Di bagian atas main.py pada inisialisasi Flask, lakukan inisialisasi Cloud NDB dan Cloud Tasks. Juga tentukan beberapa konstanta yang menunjukkan tempat tugas push Anda akan dieksekusi.

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

PROJECT_ID = 'PROJECT_ID'  # replace w/your own
REGION = 'REGION'    # replace w/your own
QUEUE_NAME = 'default'     # replace w/your own if desired
QUEUE_PATH = ts_client.queue_path(PROJECT_ID, REGION, QUEUE_NAME)

Setelah membuat task queue, isi PROJECT_ID project Anda, REGION tempat tugas akan berjalan (harus sama dengan region App Engine), dan nama push queue Anda. App Engine menampilkan queue "default", jadi kita akan menggunakan nama tersebut (tetapi Anda tidak harus).

Queue default bersifat khusus dan dibuat secara otomatis dalam situasi tertentu, salah satunya adalah saat menggunakan App Engine API, jadi jika Anda menggunakan (kembali) project yang sama dengan Modul 7, default akan sudah ada. Namun, jika membuat project baru khusus untuk Modul 8, Anda harus membuat default secara manual. Info selengkapnya tentang queue default dapat ditemukan di dokumentasi queue.yaml.

Tujuan ts_client.queue_path() adalah membuat "nama jalur yang sepenuhnya memenuhi syarat" (QUEUE_PATH) milik task queue yang diperlukan untuk membuat tugas. Selain itu, struktur JSON yang menentukan parameter tugas juga diperlukan:

task = {
    'app_engine_http_request': {
        'relative_uri': '/trim',
        'body': json.dumps({'oldest': oldest}).encode(),
        'headers': {
            'Content-Type': 'application/json',
        },
    }
}

Apa yang Anda lihat di atas?

  1. Berikan informasi target tugas:
    • Untuk target App Engine, tentukan app_engine_http_request sebagai jenis permintaan dan relative_uri adalah pengendali tugas App Engine.
    • Untuk target HTTP, gunakan http_request dan url.
  2. body: parameter yang dienkode string JSON dan Unicode yang akan dikirim ke tugas (push)
  3. Tentukan kejelasan header Content-Type yang dienkode JSON

Lihat dokumentasi untuk info selengkapnya tentang opsi Anda di sini.

Setelah penyiapan selesai, perbarui fetch_visits(). Berikut ini tampilannya dari tutorial sebelumnya:

  • SEBELUM:
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

Pembaruan yang diperlukan:

  1. Beralih dari App Engine ndb ke Cloud NDB
  2. Kode baru untuk mengekstrak stempel waktu kunjungan terlama ditampilkan
  3. Menggunakan Cloud Tasks untuk membuat tugas baru, bukan App Engine taskqueue

Seperti inilah tampilan fetch_visits() baru Anda:

  • SETELAH:
def fetch_visits(limit):
    'get most recent visits and 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

Meringkas pembaruan kode:

  • Beralih ke Cloud NDB berarti memindahkan kode Datastore dalam pernyataan with
  • Beralih ke Cloud Tasks berarti menggunakan ts_client.create_task(), bukan taskqueue.add()
  • Teruskan jalur lengkap queue dan payload task (dijelaskan sebelumnya)

Perbarui pengendali tugas (push)

Ada sangat sedikit perubahan yang perlu dilakukan pada fungsi pengendali tugas (push).

  • SEBELUM:
@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

Satu-satunya hal yang perlu dilakukan, adalah menempatkan semua akses Datastore dalam pernyataan with pengelola konteks, baik permintaan kueri maupun penghapusan. Dengan mempertimbangkan hal ini, perbarui pengendali trim() Anda seperti ini:

  • SETELAH:
@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

Tidak ada perubahan pada templates/index.html dalam hal ini atau dalam codelab berikutnya.

Deploy aplikasi

Periksa kembali semua perubahan, yang dikompilasi kode Anda, dan deploy ulang. Konfirmasi bahwa aplikasi (masih) berfungsi. Anda akan mendapatkan output yang sama dengan output dari Modul 7. Anda baru saja melakukan perbaikan, jadi seharusnya semuanya tetap berfungsi seperti yang diharapkan.

Jika Anda langsung masuk ke dalam tutorial ini tanpa melakukan codelab Modul 7, aplikasi itu sendiri tidak akan berubah. Aplikasi mendaftar semua kunjungan ke halaman web utama (/) dan tampak seperti ini setelah Anda mengunjungi situs cukup waktu dan memberi tahu Anda bahwa situs tersebut telah menghapus semua kunjungan yang lebih lama dari tanggal sepuluh:

Aplikasi visitme Modul 7

Ini mengakhiri codelab ini. Kode Anda sekarang seharusnya cocok dengan yang ada di repo Modul 8. Selamat karena telah menyelesaikan migrasi tugas push yang paling penting! Modul 9 (link codelab di bawah) bersifat opsional, membantu pengguna berpindah ke Python 3 dan Cloud Datastore.

Opsional: Pembersihan

Bagaimana dengan pembersihan agar tidak ditagih hingga Anda siap untuk beralih ke codelab migrasi berikutnya? Sebagai developer yang sudah ada, Anda mungkin sudah mengetahui yang terbaru tentang informasi harga App Engine.

Opsional: Nonaktifkan aplikasi

Jika Anda belum siap melanjutkan ke tutorial berikutnya, nonaktifkan aplikasi untuk menghindari tagihan. Jika sudah siap untuk beralih ke codelab berikutnya, Anda dapat mengaktifkannya kembali. Meskipun dinonaktifkan, aplikasi tidak akan mendapatkan traffic yang dikenakan biaya, namun hal lain yang dapat ditagih adalah penggunaan Datastore jika melebihi kuota gratis, jadi cukup hapus hingga berada di bawah batas tersebut.

Di sisi lain, jika Anda tidak akan melanjutkan migrasi dan ingin menghapus semuanya, Anda dapat mematikan project.

Langkah berikutnya

Selain tutorial ini, langkah selanjutnya adalah Modul 9 dan codelab-nya serta melakukan porting ke Python 3. Ini sedikit opsional karena tidak semua orang siap untuk langkah tersebut. Ada juga port opsional dari Cloud NDB ke Cloud Datastore - opsi ini sudah pasti bersifat opsional dan hanya bagi mereka yang ingin keluar dari NDB dan menggabungkan kode yang menggunakan Cloud Datastore. Migrasi tersebut sama dengan codelab migrasi Modul 3.

  • Modul 9 Bermigrasi dari Python 2 ke 3 dan Cloud NDB ke Cloud Datastore
    • Porting modul migrasi opsional ke Python 3
    • Juga mencakup migrasi opsional dari Cloud NDB ke Cloud Datastore (sama seperti Modul 3), dan
    • Migrasi kecil dari Cloud Tasks v1 ke v2 (karena library kliennya dibekukan untuk Python 2)
  • Modul 4: Bermigrasi ke Cloud Run dengan Docker
    • Build aplikasi dalam container untuk dijalankan di Cloud Run dengan Docker
    • Migrasi ini memungkinkan Anda untuk tetap menggunakan Python 2.
  • Modul 5: Melakukan Migrasi ke Cloud Run dengan Cloud Buildpacks
    • Build aplikasi dalam container untuk dijalankan di Cloud Run dengan Cloud Buildpacks
    • Anda tidak perlu mengetahui apa pun tentang Docker, container, atau Dockerfile.
    • Mengharuskan aplikasi Anda untuk sudah bermigrasi ke Python 3 (Buildpacks tidak mendukung Python 2)
  • Modul 6: Melakukan Migrasi ke Cloud Firestore
    • Melakukan migrasi ke Cloud Firestore untuk mengakses fitur Firebase
    • Meskipun Cloud Firestore mendukung Python 2, codelab ini hanya tersedia di Python 3.

Masalah/masukan codelab modul migrasi App Engine

Jika Anda menemukan masalah dengan codelab ini, telusuri masalah Anda terlebih dahulu sebelum mengajukan masalah. Link untuk menelusuri dan membuat masalah baru:

Resource migrasi

Link ke folder repo untuk Modul 7 (START) dan Modul 8 (FINISH) dapat ditemukan pada tabel di bawah. Link tersebut juga dapat diakses dari repo untuk semua migrasi codelab App Engine yang dapat Anda clone atau download file ZIP.

Codelab

Python 2

Python 3

Modul 7

kode

(T/A)

Modul 8

kode

(T/A)

Resource App Engine

Berikut adalah resource tambahan terkait migrasi khusus ini: