Jak korzystać z kolejki zadań App Engine (zadania push) w aplikacjach Flask (moduł 7)

1. Przegląd

Seria codelabów Serverless Migration Station (samodzielne, praktyczne samouczki) i powiązane z nimi filmy mają na celu pomóc deweloperom usług bezserwerowych Google Cloud w modernizacji aplikacji poprzez przeprowadzenie ich przez co najmniej jedną migrację, głównie z usług starszego typu. Dzięki temu Twoje aplikacje będą bardziej przenośne, a Ty zyskasz więcej opcji i elastyczności, co umożliwi Ci integrację z szerszą gamą usług w chmurze i łatwiejsze przechodzenie na nowsze wersje języka. Chociaż początkowo skupialiśmy się na pierwszych użytkownikach usług w chmurze, głównie na deweloperach App Engine (środowisko standardowe), ta seria jest wystarczająco szeroka, aby obejmować inne platformy bezserwerowe, takie jak Cloud FunctionsCloud Run, lub inne, jeśli ma to zastosowanie.

Z tego ćwiczenia w Codelabs dowiesz się, jak używać zadań push w kolejce zadań App Engine w przykładowej aplikacji z ćwiczenia w Codelabs z modułu 1. Post na blogu i film z modułu 7 uzupełniają ten samouczek, ponieważ zawierają krótkie omówienie treści w nim przedstawionych.

W tym module dodamy użycie zadań push, a następnie przeniesiemy je do Cloud Tasks w module 8, a później do Pythona 3 i Cloud Datastore w module 9. Użytkownicy korzystający z kolejek zadań do zadań typu pull przejdą na Cloud Pub/Sub i powinni zapoznać się z modułami 18–19.

Dowiesz się, jak:

  • Korzystanie z interfejsu API kolejki zadań App Engine lub usługi pakietowej
  • Dodawanie użycia zadań typu push do podstawowej aplikacji w Pythonie 2 Flask App Engine NDB

Czego potrzebujesz

Ankieta

Jak zamierzasz korzystać z tego samouczka?

Tylko przeczytaj Przeczytaj i wykonaj ćwiczenia

Jak oceniasz swoje doświadczenie z Pythonem?

Początkujący Średnio zaawansowany Zaawansowany

Jak oceniasz korzystanie z usług Google Cloud?

Początkujący Średnio zaawansowany Zaawansowany

2. Tło

Kolejka zadań App Engine obsługuje zadania push i pull. Aby zwiększyć przenośność aplikacji, zespół Google Cloud zaleca migrację z starszych usług pakietowych, takich jak kolejka zadań, na inne samodzielne usługi w chmurze lub równoważne usługi innych firm.

Migracja zadań typu pull jest omówiona w modułach 18–19, a migracja zadań typu push w modułach 7–9. Aby przeprowadzić migrację z zadań push w kolejce zadań App Engine, dodaj ich użycie do istniejącej aplikacji Flask i App Engine NDB, która powstała w wyniku wykonania ćwiczenia 1. W tej aplikacji nowe wyświetlenie strony rejestruje nową wizytę i wyświetla użytkownikowi najnowsze wizyty. Starsze wizyty nigdy nie są ponownie wyświetlane i zajmują miejsce w magazynie danych, dlatego utworzymy zadanie push, które będzie automatycznie usuwać najstarsze wizyty. W module 8 przeniesiemy tę aplikację z kolejki zadań do Cloud Tasks.

Ten samouczek obejmuje te kroki:

  1. Konfiguracja/przygotowanie
  2. Aktualizacja konfiguracji
  3. Modyfikowanie kodu aplikacji

3. Konfiguracja/przygotowanie

Z tej sekcji dowiesz się, jak:

  1. Konfigurowanie projektu w chmurze
  2. Pobieranie przykładowej aplikacji podstawowej
  3. (Ponowne) wdrażanie i weryfikowanie aplikacji podstawowej

Dzięki tym czynnościom masz pewność, że zaczynasz od działającego kodu.

1. Konfigurowanie projektu

Jeśli masz za sobą ćwiczenie z programowania w module 1, zalecamy ponowne użycie tego samego projektu (i kodu). Możesz też utworzyć zupełnie nowy projekt lub ponownie wykorzystać inny istniejący projekt. Sprawdź, czy projekt ma aktywne konto rozliczeniowe i czy usługa App Engine jest włączona.

2. Pobieranie przykładowej aplikacji podstawowej

Jednym z wymagań wstępnych tego modułu jest działająca aplikacja App Engine z modułu 1: wykonaj moduł 1 (zalecane) lub skopiuj aplikację z modułu 1 z repozytorium. Niezależnie od tego, czy używasz własnego kodu, czy naszego, kod modułu 1 to miejsce, w którym „ZACZNIEMY”. W tym Codelabs znajdziesz instrukcje krok po kroku. Na końcu znajdziesz kod podobny do tego w folderze „FINISH” w repozytorium modułu 7.

Niezależnie od tego, której aplikacji z modułu 1 używasz, folder powinien wyglądać jak poniżej. Może też zawierać folder lib:

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

3. (Ponowne) wdrażanie aplikacji bazowej

Aby (ponownie) wdrożyć aplikację z modułu 1, wykonaj te czynności:

  1. Usuń folder lib, jeśli istnieje, i uruchom polecenie: pip install -t lib -r requirements.txt, aby ponownie wypełnić folder lib. Jeśli masz zainstalowane obie wersje Pythona (2 i 3), może być konieczne użycie polecenia pip2.
  2. Sprawdź, czy narzędzie wiersza poleceń gcloud zostało zainstalowane i zainicjowane oraz czy znasz sposób jego użycia.
  3. Ustaw projekt w chmurze za pomocą polecenia gcloud config set project PROJECT_ID, jeśli nie chcesz wpisywać PROJECT_ID przy każdym wydaniu polecenia gcloud.
  4. Wdrażanie przykładowej aplikacji za pomocą gcloud app deploy
  5. Sprawdź, czy aplikacja Moduł 1 działa zgodnie z oczekiwaniami i wyświetla najnowsze wizyty (jak na ilustracji poniżej).

a7a9d2b80d706a2b.png

4. Aktualizacja konfiguracji

Nie trzeba wprowadzać żadnych zmian w standardowych plikach konfiguracyjnych App Engine (app.yaml, requirements.txt, appengine_config.py).

5. Modyfikowanie plików aplikacji

Główny plik aplikacji to main.py, a wszystkie aktualizacje w tej sekcji dotyczą tego pliku. Wprowadziliśmy też niewielką aktualizację szablonu internetowego templates/index.html. Oto zmiany, które należy wprowadzić w tej sekcji:

  1. Aktualizowanie importów
  2. Dodawanie zadania push
  3. Dodawanie modułu obsługi zadań
  4. Aktualizowanie szablonu internetowego

1. Aktualizowanie importów

Importowanie google.appengine.api.taskqueue powoduje włączenie funkcji kolejki zadań. Wymagane są też niektóre pakiety standardowej biblioteki Pythona:

  • Dodajemy zadanie usuwania najstarszych wizyt, więc aplikacja będzie musiała obsługiwać sygnatury czasowe, co oznacza użycie znaków timedatetime.
  • Aby rejestrować przydatne informacje dotyczące wykonywania zadań, potrzebujemy logging.

Po dodaniu wszystkich tych instrukcji importu kod będzie wyglądać tak jak poniżej:

PRZED:

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

PO:

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. Dodawanie zadania push (zbieranie danych do zadania, umieszczanie nowego zadania w kolejce)

W dokumentacji kolejki push jest napisane: „Aby przetworzyć zadanie, musisz dodać je do kolejki push. App Engine udostępnia domyślną kolejkę push o nazwie default, która jest skonfigurowana i gotowa do użycia z ustawieniami domyślnymi. Jeśli chcesz, możesz po prostu dodać wszystkie zadania do domyślnej kolejki bez konieczności tworzenia i konfigurowania innych kolejek”. W tym laboratorium używamy kolejki default, aby skrócić czas oczekiwania. Więcej informacji o definiowaniu własnych kolejek push o takich samych lub różnych cechach znajdziesz w dokumentacji tworzenia kolejek push.

Głównym celem tego laboratorium jest dodanie zadania (do default kolejki push), które będzie usuwać z Datastore stare wizyty, które nie są już wyświetlane. Aplikacja podstawowa rejestruje każdą wizytę (GET żądanie do /), tworząc nowy Visit element, a następnie pobiera i wyświetla najnowsze wizyty. Żadne z najstarszych odwiedzin nie będą już wyświetlane ani używane, więc zadanie push usuwa wszystkie odwiedziny starsze niż najstarsze wyświetlane. Aby to osiągnąć, musisz nieco zmienić działanie aplikacji:

  1. Podczas wysyłania zapytań o najnowsze wizyty zamiast od razu zwracać te wizyty zmodyfikuj aplikację tak, aby zapisywała sygnaturę czasową ostatniej Visit, najstarszej wyświetlanej wizyty – wszystkie wizyty starsze niż ta można bezpiecznie usunąć.
  2. Utwórz zadanie push z tym sygnaturą czasową jako ładunkiem i skieruj je do modułu obsługi zadań dostępnego przez HTTP POST do /trim. Użyj standardowych narzędzi Pythona, aby przekonwertować sygnaturę czasową Datastore i wysłać ją (jako liczbę zmiennoprzecinkową) do zadania, a także zalogować ją (jako ciąg znaków) i zwrócić ten ciąg znaków jako wartość wartowniczą do wyświetlenia użytkownikowi.

Wszystko to odbywa się w fetch_visits(). Tak wygląda to przed i po wprowadzeniu tych zmian:

PRZED:

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

PO:

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. Dodaj moduł obsługi zadania (kod wywoływany podczas wykonywania zadania)

Usuwanie starych wizyt można było łatwo zrealizować w fetch_visits(), ale pamiętaj, że ta funkcja nie ma wiele wspólnego z użytkownikiem końcowym. Jest to funkcja pomocnicza, która dobrze nadaje się do przetwarzania asynchronicznego poza standardowymi żądaniami aplikacji. Użytkownik końcowy skorzysta na szybszych zapytaniach, ponieważ w magazynie danych będzie mniej informacji. Utwórz nową funkcję trim(), wywoływaną za pomocą żądania kolejki zadań POST do /trim, która wykonuje te czynności:

  1. Wyodrębnia ładunek sygnatury czasowej „najstarszej wizyty”.
  2. Wysyła zapytanie do Datastore, aby znaleźć wszystkie encje starsze niż ta sygnatura czasowa.
  3. Wybiera szybsze zapytanie „tylko klucze”, ponieważ nie są potrzebne żadne rzeczywiste dane użytkownika.
  4. Rejestruje liczbę elementów do usunięcia (w tym zero).
  5. Wywołania ndb.delete_multi() w celu usunięcia wszystkich elementów (pomijane, jeśli nie ma takich elementów).
  6. Zwraca pusty ciąg znaków (wraz z domniemanym kodem zwrotu HTTP 200).

Wszystkie te informacje znajdziesz w sekcji trim() poniżej. Dodaj go do main.py tuż po 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. Aktualizowanie szablonu internetowego

Zaktualizuj szablon internetowy templates/index.html za pomocą tego warunku Jinja2, aby wyświetlać najstarszą sygnaturę czasową, jeśli ta zmienna istnieje:

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

Dodaj ten fragment kodu po wyświetlonej liście wizyt, ale przed zamknięciem treści, aby szablon wyglądał tak:

<!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. Podsumowanie i czyszczenie

W tej sekcji podsumowujemy te warsztaty, wdrażając aplikację i sprawdzając, czy działa zgodnie z oczekiwaniami i czy dane wyjściowe są prawidłowe. Po zweryfikowaniu aplikacji wykonaj czyszczenie i rozważ kolejne kroki.

Wdrażanie i weryfikowanie aplikacji

Wdróż aplikację za pomocą gcloud app deploy. Dane wyjściowe powinny być identyczne z aplikacją z modułu 1, z wyjątkiem nowego wiersza u dołu, w którym wyświetlają się informacje o wizytach, które zostaną usunięte:

4aa8a2cb5f527079.png

Gratulujemy ukończenia ćwiczenia. Kod powinien teraz być zgodny z tym w folderze repozytorium modułu 7. Możesz teraz przejść na Cloud Tasks w module 8.

Czyszczenie danych

Ogólne

Jeśli na razie nie chcesz już korzystać z usługi, zalecamy wyłączenie aplikacji App Engine, aby uniknąć naliczania opłat. Jeśli jednak chcesz przeprowadzić więcej testów lub eksperymentów, platforma App Engine ma bezpłatny limit, więc dopóki nie przekroczysz tego poziomu wykorzystania, nie powinny być naliczane żadne opłaty. Dotyczy to obliczeń, ale mogą też wystąpić opłaty za odpowiednie usługi App Engine, więc więcej informacji znajdziesz na stronie z cennikiem. Jeśli migracja obejmuje inne usługi w chmurze, są one rozliczane oddzielnie. W każdym przypadku, jeśli to konieczne, zapoznaj się z sekcją „Specyficzne dla tego laboratorium” poniżej.

Wdrożenie na bezserwerowej platformie obliczeniowej Google Cloud, takiej jak App Engine, wiąże się z niewielkimi kosztami kompilacji i przechowywania. Cloud Build ma własny bezpłatny limit, podobnie jak Cloud Storage. Przechowywanie tego obrazu wykorzystuje część tego limitu. Możesz jednak mieszkać w regionie, w którym nie ma takiego bezpłatnego pakietu, więc kontroluj wykorzystanie miejsca na dane, aby zminimalizować potencjalne koszty. Sprawdź te „foldery” Cloud Storage:

  • 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
  • Linki do pamięci masowej powyżej zależą od PROJECT_ID i *LOC*acji, np. „us”, jeśli Twoja aplikacja jest hostowana w Stanach Zjednoczonych.

Jeśli nie zamierzasz kontynuować pracy z tą aplikacją ani innymi powiązanymi z nią samouczkami dotyczącymi migracji i chcesz wszystko całkowicie usunąć, wyłącz projekt.

Dotyczy tych ćwiczeń z programowania

Usługi wymienione poniżej są dostępne tylko w tym laboratorium. Więcej informacji znajdziesz w dokumentacji poszczególnych usług:

Dalsze kroki

W ramach tej „migracji” dodaliśmy do przykładowej aplikacji z modułu 1 użycie kolejki push Task Queue, co umożliwiło śledzenie odwiedzających. W ten sposób powstała przykładowa aplikacja z modułu 7. Z kolejnej migracji dowiesz się, jak w razie potrzeby przejść z zadań push App Engine na Cloud Tasks. Jesienią 2021 r. użytkownicy nie musieli już migrować do Cloud Tasks podczas uaktualniania do Pythona 3. Więcej informacji na ten temat znajdziesz w następnej sekcji.

Jeśli chcesz przejść na Cloud Tasks, następny jest samouczek z modułu 8. Oprócz tego warto rozważyć dodatkowe migracje, takie jak Cloud Datastore, Cloud Memorystore, Cloud Storage czy Cloud Pub/Sub (kolejki pobierania). Istnieją też migracje między usługami do Cloud Run i Cloud Functions. Cała zawartość Serverless Migration Station (ćwiczenia z programowania, filmy, kod źródłowy [jeśli jest dostępny]) jest dostępna w repozytorium open source.

7. Migracja do Pythona 3

Jesienią 2021 r. zespół App Engine rozszerzył obsługę wielu usług pakietowych na środowiska wykonawcze 2 generacji (pierwotnie dostępne tylko w środowiskach wykonawczych 1 generacji), co oznacza, że podczas przenoszenia aplikacji do Pythona 3 nie musisz już migrować z usług pakietowych, takich jak kolejka zadań App Engine, do samodzielnych usług Cloud lub odpowiedników innych firm, takich jak Cloud Tasks. Innymi słowy, możesz nadal używać kolejki zadań w aplikacjach App Engine w Pythonie 3, o ile dostosujesz kod, aby uzyskać dostęp do usług pakietowych ze środowisk wykonawczych nowej generacji.

Więcej informacji o przenoszeniu korzystania z usług pakietowych do Pythona 3 znajdziesz w ćwiczeniu programistycznym w module 17 i odpowiednim filmie. Ten temat wykracza poza zakres modułu 7, ale poniżej znajdziesz wersje aplikacji z modułów 1 i 7 w języku Python 3, które nadal korzystają z NDB App Engine i kolejki zadań.

8. Dodatkowe materiały

Poniżej znajdziesz dodatkowe materiały dla programistów, którzy chcą dowiedzieć się więcej o tym lub powiązanym module migracji, a także o powiązanych produktach. Znajdziesz tu m.in. miejsca, w których możesz przesłać opinię o tych treściach, linki do kodu i różne dokumenty, które mogą Ci się przydać.

Problemy z ćwiczeniami z programowania i opinie na ich temat

Jeśli zauważysz jakieś problemy z tym kursem, najpierw poszukaj rozwiązania, a dopiero potem zgłoś problem. Linki do wyszukiwania i tworzenia nowych problemów:

Materiały dotyczące migracji

Linki do folderów repozytorium dla modułu 2 (START) i modułu 7 (FINISH) znajdziesz w tabeli poniżej.

Ćwiczenia z programowania

Python 2

Python 3

Moduł 1

kod

kod (nie jest omawiany w tym samouczku)

Moduł 7 (te ćwiczenia z programowania)

kod

kod (nie jest omawiany w tym samouczku)

Zasoby online

Poniżej znajdziesz zasoby online, które mogą być przydatne w tym samouczku:

Kolejka zadań App Engine

Platforma App Engine

Inne informacje o chmurze

Filmy

Licencja

To zadanie jest licencjonowane na podstawie ogólnej licencji Creative Commons Attribution 2.0.