Cloud Run-Funktionen mit Cloud Tasks auslösen


In dieser Anleitung erfahren Sie, wie Sie mit Cloud Tasks in einer App Engine-Anwendung eine Cloud Run-Funktion auslösen und eine geplante E-Mail senden.

Lernziele

  • Machen Sie sich mit dem Code der einzelnen Komponenten vertraut.
  • Ein SendGrid-Konto erstellen
  • Herunterladen des Quellcodes
  • Stellen Sie eine Cloud Run-Funktion bereit, um Cloud Tasks-Anfragen zu empfangen und eine E-Mail über die SendGrid API zu senden.
  • Erstellen Sie eine Cloud Tasks-Warteschlange.
  • Erstellen Sie ein Dienstkonto, um Ihre Cloud Tasks-Anfragen zu authentifizieren.
  • Stellen Sie den Clientcode bereit, mit dem ein Nutzer eine E-Mail senden kann.

Kosten

Cloud Tasks, Cloud Run-Funktionen und App Engine haben eine kostenlose Stufe. Solange Sie die Anleitung innerhalb der kostenlosen Stufe der angegebenen Produkte ausführen, sollten keine zusätzlichen Kosten anfallen. Weitere Informationen finden Sie unter Preise.

Hinweise

  1. Wählen Sie ein Google Cloud-Projekt aus oder erstellen Sie eines.

    Zur Seite "App Engine"

  2. Initialisieren Sie eine App Engine-Anwendung in Ihrem Projekt:

    1. Klicken Sie auf der Seite Willkommen bei App Engine auf Anwendung erstellen.

    2. Wählen Sie eine Region für Ihre Anwendung aus. Notieren Sie diesen Standort. Er wird als LOCATION_ID-Parameter für Ihre Cloud Tasks-Anfragen verwendet. Die zwei Standorte der App Engine-Befehle europe-west und us-central werden in den Cloud Tasks-Befehlen europe-west1 und us-central1 genannt.

    3. Wählen Sie Node.js als Sprache und Standard als Umgebung aus.

    4. Falls das Pop-up-Fenster Abrechnung aktivieren angezeigt wird, wählen Sie Ihr Rechnungskonto aus. Wenn Sie noch kein Rechnungskonto haben, klicken Sie auf Rechnungskonto erstellen und folgen Sie den Anweisungen des Assistenten.

    5. Klicken Sie auf der Seite Erste Schritte auf Nächste. Sie werden sich später darum kümmern.

  3. Aktivieren Sie die Cloud Run Functions und Cloud Tasks APIs.

    APIs aktivieren

  4. Installieren und initialisieren Sie die gcloud CLI.

Code verstehen

In diesem Abschnitt werden der App-Code und dessen Funktionsweise erläutert.

Aufgabe erstellen

Die Indexseite wird mithilfe von Handlern in app.yaml bereitgestellt. Die für die Aufgabenerstellung erforderlichen Variablen werden als Umgebungsvariablen übergeben.

runtime: nodejs16

env_variables:
  QUEUE_NAME: "my-queue"
  QUEUE_LOCATION: "us-central1"
  FUNCTION_URL: "https://<region>-<project_id>.cloudfunctions.net/sendEmail"
  SERVICE_ACCOUNT_EMAIL: "<member>@<project_id>.iam.gserviceaccount.com"

# Handlers for serving the index page.
handlers:
  - url: /static
    static_dir: static
  - url: /
    static_files: index.html
    upload: index.html

Dieser Code erstellt den Endpunkt /send-email. Dieser Endpunkt verarbeitet Formularübermittlungen von der Indexseite und leitet diese Daten an den Aufgabenerstellungscode weiter.

app.post('/send-email', (req, res) => {
  // Set the task payload to the form submission.
  const {to_name, from_name, to_email, date} = req.body;
  const payload = {to_name, from_name, to_email};

  createHttpTaskWithToken(
    process.env.GOOGLE_CLOUD_PROJECT,
    QUEUE_NAME,
    QUEUE_LOCATION,
    FUNCTION_URL,
    SERVICE_ACCOUNT_EMAIL,
    payload,
    date
  );

  res.status(202).send('📫 Your postcard is in the mail! 💌');
});

Dieser Code erstellt die Aufgabe und sendet sie an die Cloud Tasks-Warteschlange. So erstellt der Code die Aufgabe:

  • Angabe des Zieltyps als HTTP Request.

  • Angabe des zu verwendenden HTTP method und des URL des Ziels.

  • Einstellen der Content-Type header to application/json Downstream-Anwendungen kann die strukturierte Nutzlast parsen.

  • E-Mail-Konto für Dienstkonto hinzufügen, damit Cloud Tasks Anmeldedaten für das Anforderungsziel bereitstellen kann, für das eine Authentifizierung erforderlich ist. Das Dienstkonto wird separat erstellt.

  • Prüfen, ob die Nutzereingabe für das Datum innerhalb der maximalen 30 Tage liegt, und der Anfrage als Feld scheduleTime hinzufügen.

const MAX_SCHEDULE_LIMIT = 30 * 60 * 60 * 24; // Represents 30 days in seconds.

const createHttpTaskWithToken = async function (
  project = 'my-project-id', // Your GCP Project id
  queue = 'my-queue', // Name of your Queue
  location = 'us-central1', // The GCP region of your queue
  url = 'https://example.com/taskhandler', // The full url path that the request will be sent to
  email = '<member>@<project-id>.iam.gserviceaccount.com', // Cloud IAM service account
  payload = 'Hello, World!', // The task HTTP request body
  date = new Date() // Intended date to schedule task
) {
  // Imports the Google Cloud Tasks library.
  const {v2beta3} = require('@google-cloud/tasks');

  // Instantiates a client.
  const client = new v2beta3.CloudTasksClient();

  // Construct the fully qualified queue name.
  const parent = client.queuePath(project, location, queue);

  // Convert message to buffer.
  const convertedPayload = JSON.stringify(payload);
  const body = Buffer.from(convertedPayload).toString('base64');

  const task = {
    httpRequest: {
      httpMethod: 'POST',
      url,
      oidcToken: {
        serviceAccountEmail: email,
        audience: url,
      },
      headers: {
        'Content-Type': 'application/json',
      },
      body,
    },
  };

  const convertedDate = new Date(date);
  const currentDate = new Date();

  // Schedule time can not be in the past.
  if (convertedDate < currentDate) {
    console.error('Scheduled date in the past.');
  } else if (convertedDate > currentDate) {
    const date_diff_in_seconds = (convertedDate - currentDate) / 1000;
    // Restrict schedule time to the 30 day maximum.
    if (date_diff_in_seconds > MAX_SCHEDULE_LIMIT) {
      console.error('Schedule time is over 30 day maximum.');
    }
    // Construct future date in Unix time.
    const date_in_seconds =
      Math.min(date_diff_in_seconds, MAX_SCHEDULE_LIMIT) + Date.now() / 1000;
    // Add schedule time to request in Unix time using Timestamp structure.
    // https://googleapis.dev/nodejs/tasks/latest/google.protobuf.html#.Timestamp
    task.scheduleTime = {
      seconds: date_in_seconds,
    };
  }

  try {
    // Send create task request.
    const [response] = await client.createTask({parent, task});
    console.log(`Created task ${response.name}`);
    return response.name;
  } catch (error) {
    // Construct error for Stackdriver Error Reporting
    console.error(Error(error.message));
  }
};

module.exports = createHttpTaskWithToken;

E-Mail erstellen

Mit diesem Code wird die Cloud Run-Funktion erstellt, die das Ziel für die Cloud Tasks-Anfrage ist. Es verwendet den Anfragetext, um eine E-Mail zu erstellen und über die SendGrid API zu senden.

const sendgrid = require('@sendgrid/mail');

/**
 * Responds to an HTTP request from Cloud Tasks and sends an email using data
 * from the request body.
 *
 * @param {object} req Cloud Function request context.
 * @param {object} req.body The request payload.
 * @param {string} req.body.to_email Email address of the recipient.
 * @param {string} req.body.to_name Name of the recipient.
 * @param {string} req.body.from_name Name of the sender.
 * @param {object} res Cloud Function response context.
 */
exports.sendEmail = async (req, res) => {
  // Get the SendGrid API key from the environment variable.
  const key = process.env.SENDGRID_API_KEY;
  if (!key) {
    const error = new Error(
      'SENDGRID_API_KEY was not provided as environment variable.'
    );
    error.code = 401;
    throw error;
  }
  sendgrid.setApiKey(key);

  // Get the body from the Cloud Task request.
  const {to_email, to_name, from_name} = req.body;
  if (!to_email) {
    const error = new Error('Email address not provided.');
    error.code = 400;
    throw error;
  } else if (!to_name) {
    const error = new Error('Recipient name not provided.');
    error.code = 400;
    throw error;
  } else if (!from_name) {
    const error = new Error('Sender name not provided.');
    error.code = 400;
    throw error;
  }

  // Construct the email request.
  const msg = {
    to: to_email,
    from: 'postcard@example.com',
    subject: 'A Postcard Just for You!',
    html: postcardHTML(to_name, from_name),
  };

  try {
    await sendgrid.send(msg);
    // Send OK to Cloud Task queue to delete task.
    res.status(200).send('Postcard Sent!');
  } catch (error) {
    // Any status code other than 2xx or 503 will trigger the task to retry.
    res.status(error.code).send(error.message);
  }
};

Anwendung vorbereiten

SendGrid einrichten

  1. Ein SendGrid-Konto erstellen

  2. Erstellen Sie einen SendGrid API-Schlüssel:

    1. Melden Sie sich bei Ihrem SendGrid-Konto an.

    2. Öffnen Sie im linken Navigationsbereich Einstellungen und klicken Sie auf API-Schlüssel.

    3. Klicken Sie auf API-Schlüssel erstellen und wählen Sie den eingeschränkten Zugriff aus. Wählen Sie unter dem Header E-Mail senden Vollständiger Zugriff aus.

    4. Kopieren Sie den API-Schlüssel (er wird nur einmal angezeigt) in ein Dokument, um am Ende der Anleitung, wenn Sie die Cloud Functions-Funktionen aufrufen, darauf zurückgreifen zu können.

Quellcode herunterladen

  1. Klonen Sie das Repository der Beispiel-App auf Ihren lokalen Computer:

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git
    
  2. Wechseln Sie zu dem Verzeichnis, das den Beispielcode enthält:

    cd cloud-tasks/
    

Cloud Run-Funktion bereitstellen

  1. Rufen Sie das Verzeichnis function/ auf:

    cd function/
    
  2. Die Funktion bereitstellen:

    gcloud functions deploy sendEmail --runtime nodejs14 --trigger-http \
      --no-allow-unauthenticated \
      --set-env-vars SENDGRID_API_KEY=SENDGRID_API_KEY \

    Ersetzen Sie dabei SENDGRID_API_KEY durch Ihren eigenen API-Schlüssel.

    Dieser Befehl verwendet Flags:

    • --trigger-http zum Angeben des Triggertyps für Cloud Run-Funktionen.

    • --no-allow-unauthenticated, um anzugeben, dass für den Funktionsaufruf eine Authentifizierung erforderlich ist.

    • --set-env-var, um Ihre SendGrid-Anmeldedaten festzulegen

  3. Legen Sie die Zugriffssteuerung für die Funktion so fest, dass nur authentifizierte Nutzer zugelassen werden.

    1. Wählen Sie in der Cloud Run-Funktions-Benutzeroberfläche die Funktion sendEmail aus.

    2. Wenn Sie keine Informationen zu Berechtigungen für sendEmail sehen, klicken Sie rechts oben auf Infofeld ansehen.

    3. Klicken Sie oben auf die Schaltfläche Hauptkonten hinzufügen.

    4. Legen Sie Neue Hauptkonten auf allAuthenticatedUsers fest.

    5. Legen Sie die Rolle fest.

      • Funktionen der ersten Generation (1. Generation): Legen Sie die Rolle auf Cloud Function Invoker fest.
      • Funktionen der zweiten Generation (2. Generation): Legen Sie die Rolle auf Cloud Run Invoker fest.
    6. Klicken Sie auf SPEICHERN.

Cloud Tasks-Warteschlange erstellen

  1. Erstellen Sie eine Warteschlange mit dem folgenden Befehl gcloud:

    gcloud tasks queues create my-queue --location=LOCATION

    Ersetzen Sie LOCATION durch den gewünschten Speicherort für die Warteschlange, z. B. us-west2. Wenn Sie den Speicherort nicht angeben, wird der Standardspeicherort der gcloud CLI verwendet.

  2. Prüfen Sie, ob sie erfolgreich erstellt wurde:

    gcloud tasks queues describe my-queue --location=LOCATION

    Ersetzen Sie LOCATION durch den Speicherort der Warteschlange.

Dienstkonto erstellen

Die Cloud Tasks-Anfrage muss im Authorization-Header Anmeldedaten angeben, damit die Cloud Run-Funktion die Anfrage authentifizieren kann. Mit diesem Dienstkonto kann Cloud Tasks zu diesem Zweck ein OIDC-Token erstellen und hinzufügen.

  1. Klicken Sie auf der Benutzeroberfläche für Dienstkonten auf + DIENSTKONTO ERSTELLEN.

  2. Fügen Sie einen Dienstkontonamen(Anzeigename) hinzu und wählen Sie Erstellen aus.

  3. Legen Sie die Rolle fest und klicken Sie auf Weiter.

    • Funktionen der 1. Generation: Legen Sie die Rolle auf Cloud Function Invoker fest.
    • Funktionen der zweiten Generation (2. Generation): Legen Sie die Rolle auf Cloud Run Invoker fest.
  4. Wählen Sie Fertig aus.

Endpunkt und Aufgabenersteller in App Engine bereitstellen

  1. Gehen Sie zum Verzeichnis app/:

    cd ../app/
    
  2. Aktualisieren Sie Variablen in app.yaml mit Ihren Werten:

    env_variables:
      QUEUE_NAME: "my-queue"
      QUEUE_LOCATION: "us-central1"
      FUNCTION_URL: "https://<region>-<project_id>.cloudfunctions.net/sendEmail"
      SERVICE_ACCOUNT_EMAIL: "<member>@<project_id>.iam.gserviceaccount.com"

    Verwenden Sie den folgenden Befehl, um den Speicherort Ihrer Warteschlange zu ermitteln:

    gcloud tasks queues describe my-queue --location=LOCATION

    Ersetzen Sie LOCATION durch den Speicherort der Warteschlange.

    Verwenden Sie den folgenden Befehl, um die Funktions-URL zu ermitteln:

    gcloud functions describe sendEmail
  3. Stellen Sie die Anwendung mit dem folgenden Befehl in der App Engine-Standardumgebung bereit:

    gcloud app deploy
  4. Öffnen Sie die Anwendung, um eine Postkarte als E-Mail zu senden:

    gcloud app browse

Bereinigen

Nachdem Sie die Anleitung abgeschlossen haben, können Sie die erstellten Ressourcen bereinigen, damit sie keine Kontingente mehr nutzen und keine Gebühren mehr anfallen. In den folgenden Abschnitten erfahren Sie, wie Sie diese Ressourcen löschen oder deaktivieren.

Ressourcen löschen

Sie können die Ressourcen bereinigen, die Sie in Google Cloud erstellt haben, damit sie kein Kontingent verbrauchen und Ihnen in Zukunft nicht in Rechnung gestellt werden. In den folgenden Abschnitten wird erläutert, wie Sie diese Ressourcen löschen oder deaktivieren.

Cloud Run-Funktion löschen

  1. Rufen Sie in der Google Cloud Console die Seite Cloud Run-Funktionen auf.

    Rufen Sie die Seite „Cloud Run-Funktionen“ auf.

  2. Klicken Sie die Kästchen neben Ihren Funktionen an.

  3. Klicken Sie oben auf der Seite auf Löschen und bestätigen Sie den Löschvorgang.

Cloud Tasks-Warteschlange löschen

  1. Öffnen Sie in der Console die Seite mit den Cloud Tasks-Warteschlangen.

    Weiter zur Seite mit den Cloud Tasks-Warteschlangen

  2. Wählen Sie den Namen der Warteschlange aus, die Sie löschen möchten, und klicken Sie auf Warteschlange löschen.

  3. Bestätigen Sie die Aktion.

Projekt löschen

Am einfachsten vermeiden Sie weitere Kosten, wenn Sie das zum Ausführen der Anleitung erstellte Projekt löschen.

So löschen Sie das Projekt:

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Nächste Schritte