Asynchrone Aufgaben ausführen

Mit Cloud Tasks können Sie eine Aufgabe sicher in die Warteschlange stellen, damit sie von einem Cloud Run-Dienst asynchron verarbeitet werden kann. Zu den typischen Anwendungsfällen gehören:

  • Anfragen durch unerwartete Produktionsvorfälle beibehalten
  • Traffic-Spitzen durch Verzögerung von Aufgaben ausgleichen, die nicht von Nutzern wahrgenommen werden
  • Nutzerantwortzeit durch Delegieren langsamer Hintergrundvorgänge beschleunigen, die von einem anderen Dienst verarbeitet werden, z. B. Datenbankaktualisierungen oder Batchverarbeitung
  • Aufrufrate von Back-up-Diensten wie Datenbanken und APIs von Drittanbietern beschränken

Auf dieser Seite wird gezeigt, wie Aufgaben, die sicher über das HTTPS-Protokoll an einen privaten Cloud Run-Dienst übertragen werden, in die Warteschlange gestellt werden. Sie beschreibt das erforderliche Verhalten für den privaten Cloud Run-Dienst, die erforderlichen Dienstkontoberechtigungen und die Erstellung von Aufgabenwarteschlangen und Aufgaben.

Hinweis

Aktivieren Sie die Cloud Tasks API für das Projekt, das Sie verwenden.

Cloud Run-Dienst zur Verarbeitung von Aufgaben bereitstellen

Wenn Sie einen Dienst bereitstellen möchten, der Aufgaben akzeptiert, die an die Aufgabenwarteschlange gesendet wurden, stellen Sie den Dienst genau wie jeden anderen Cloud Run-Dienst bereit. Der Cloud Run-Dienst muss einen HTTP200-Code zurückgeben, um den Erfolg nach Abschluss der Aufgabenverarbeitung zu bestätigen.

Aufgaben werden als HTTPS-Anfragen von Cloud Tasks an diesen Cloud Run-Dienst übertragen.

Die Antwort auf Cloud Tasks muss innerhalb des konfigurierten Zeitlimits erfolgen. Verwenden Sie für Arbeitslasten, die länger als das maximale Cloud Tasks-Zeitlimit ausgeführt werden müssen, die Verwendung von Cloud Run-Jobs.

Mit Terraform bereitstellen

Informationen zum Anwenden oder Entfernen einer Terraform-Konfiguration finden Sie unter Grundlegende Terraform-Befehle.

Fügen Sie der .tf-Datei Folgendes hinzu, um einen Dienst zu erstellen:

resource "google_cloud_run_v2_service" "default" {
  name     = "cloud-run-task-service"
  location = "us-central1"

  deletion_protection = false # set to "true" in production

  template {
    containers {
      image = "us-docker.pkg.dev/cloudrun/container/hello"
    }
  }
}

Eine Aufgabenwarteschlange erstellen

Befehlszeile

Verwenden Sie den folgenden Befehl, um eine Aufgabenwarteschlange zu erstellen:

gcloud tasks queues create QUEUE-ID

Ersetzen Sie QUEUE-ID durch den Namen, den Sie der Aufgabenwarteschlange geben möchten. Er muss in Ihrem Projekt eindeutig sein. Wenn Sie aufgefordert werden, eine App Engine-Anwendung in Ihrem Projekt zu erstellen, antworten Sie mit y, um sie zu erstellen. Cloud Tasks verwendet dies für die Warteschlange. Sie müssen dabei denselben Speicherort auswählen, den Sie für Ihren Cloud Run-Dienst verwenden.

Die Standardkonfiguration für Aufgabenwarteschlangen sollte in den meisten Fällen funktionieren. Sie können jedoch bei Bedarf andere Ratenbegrenzungen und Wiederholungsparameter festlegen.

Terraform

Informationen zum Anwenden oder Entfernen einer Terraform-Konfiguration finden Sie unter Grundlegende Terraform-Befehle.

Fügen Sie der .tf-Datei Folgendes hinzu, um eine Aufgabenwarteschlange zu erstellen:

resource "google_cloud_tasks_queue" "default" {
  name     = "cloud-tasks-queue-name"
  location = "us-central1"
}

Um die Änderungen anzuwenden, geben Sie terraform apply ein.

Dienstkonto erstellen, das mit den Aufgaben verknüpft werden soll

Sie müssen ein Dienstkonto erstellen, das den Aufgaben in der Warteschlange zugewiesen wird. Dieses Dienstkonto muss über die IAM-Rolle "Cloud Run-Invoker" verfügen, damit die Aufgabenwarteschlange Aufgaben an den Cloud Run-Dienst übertragen kann. .

Console

  1. Rufen Sie in der Google Cloud Console die Seite Dienstkonten auf:

    Zur Seite „Dienstkonten“

  2. Wählen Sie ein Projekt aus.

  3. Geben Sie einen Dienstkontonamen ein, der in der Google Cloud Console angezeigt werden soll.

    Die Google Cloud Console generiert anhand dieses Namens eine Dienstkonto-ID. Bearbeiten Sie gegebenenfalls die ID. Sie können die ID später nicht mehr ändern.

  4. Optional: Geben Sie eine Beschreibung für das Dienstkonto ein.

  5. Klicken Sie auf Erstellen und fortfahren.

  6. Optional: Klicken Sie auf das Feld Rolle auswählen.

  7. Wählen Sie Cloud Run > Cloud Run Invoker aus.

  8. Klicken Sie auf Fertig.

Befehlszeile

  1. Erstellen Sie das Dienstkonto:

    gcloud iam service-accounts create SERVICE_ACCOUNT_NAME \
       --display-name "DISPLAYED_SERVICE_ACCOUNT_NAME"

    Ersetzen

    • SERVICE_ACCOUNT_NAME durch einen Namen in Kleinbuchstaben, der in Ihrem Google Cloud-Projekt eindeutig ist, z. B. my-invoker-service-account-name.
    • DISPLAYED_SERVICE_ACCOUNT_NAME durch den Namen, den Sie für dieses Dienstkonto anzeigen möchten, z. B. in der Konsole wie etwa My Invoker Service Account.
  2. Erteilen Sie Ihrem Dienstkonto für Cloud Run die Berechtigung, den Dienst aufzurufen:

    gcloud run services add-iam-policy-binding SERVICE \
       --member=serviceAccount:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com \
       --role=roles/run.invoker

    Ersetzen

    • SERVICE durch den Namen des Dienstes, der von Cloud Tasks aufgerufen werden soll.
    • SERVICE_ACCOUNT_NAME durch den Namen des Dienstkontos.
    • PROJECT_ID durch Ihre Google Cloud-Projekt-ID.
  3. Gewähren Sie Ihrem Dienstkonto Zugriff auf das Projekt, damit es berechtigt ist, bestimmte Aktionen für die Ressourcen in Ihrem Projekt auszuführen:

    gcloud projects add-iam-policy-binding RESOURCE_ID \
       --member=PRINCIPAL --role=roles/run.invoker

    Ersetzen

    • RESOURCE_ID: Ihre Google Cloud-Projekt-ID.

    • PRINCIPAL: Eine Kennung für das Hauptkonto bzw. Mitglied, die normalerweise die folgende Form hat: PRINCIPAL_TYPE:ID. Beispiel: user:my-user@example.com. Eine vollständige Liste der für PRINCIPAL zulässigen Werte finden Sie in der Referenz zur Richtlinienbindung.

Terraform

Informationen zum Anwenden oder Entfernen einer Terraform-Konfiguration finden Sie unter Grundlegende Terraform-Befehle.

Fügen Sie der Datei .tf Folgendes hinzu:

Erstellen Sie das Dienstkonto:

resource "google_service_account" "default" {
  account_id   = "cloud-run-task-invoker"
  display_name = "Cloud Run Task Invoker"
}

Erteilen Sie Ihrem Dienstkonto für Cloud Run die Berechtigung, den Dienst aufzurufen:

resource "google_cloud_run_service_iam_binding" "default" {
  location = google_cloud_run_v2_service.default.location
  service  = google_cloud_run_v2_service.default.name
  role     = "roles/run.invoker"
  members  = ["serviceAccount:${google_service_account.default.email}"]
}

Um die Änderungen anzuwenden, geben Sie terraform apply ein.

HTTP-Aufgaben mit Authentifizierungstokens erstellen

Wenn Sie eine Aufgabe zum Senden an die Aufgabenwarteschlange erstellen, geben Sie das Projekt, den Speicherort, den Warteschlangennamen, die mit Aufgaben zu verknüpfende E-Mail des zuvor erstellten Dienstkontos, die URL des privaten Cloud Run-Dienstes, der die Aufgabe ausführt, und die anderen Daten an, die gesendet werden müssen. Sie können diese Werte hartcodieren, wobei Werte wie Projekt-ID, Standort und E-Mail-Adresse des Dienstkontos aus demCloud Run-Metadatenserver dynamisch abgerufen werden können.

Weitere Informationen zum Anfragetext der Aufgabe finden Sie in der Dokumentation zur Cloud Tasks API. Anfragen, die Datennutzlasten enthalten, müssen die HTTP-Methode PUT oder POST verwenden.

Der Code, mit dem die Aufgaben in die Warteschlange gestellt werden, muss über die erforderlichen IAM-Berechtigungen verfügen, z. B. die Rolle "Cloud Tasks-Ersteller". Ihr Code verfügt über die erforderlichen IAM-Berechtigungen, wenn Sie das Standarddienstkonto in Cloud Run verwenden.

In den folgenden Beispielen werden Aufgabenanfragen beschrieben, die auch die Erstellung eines Header-Tokens umfassen. In den Beispielen werden OIDC-Token verwendet. Wenn Sie ein OAuth-Token verwenden, ersetzen Sie den OIDC-Parameter beim Erstellen der Anfrage durch den sprachspezifischen OAuth-Parameter.

Python

from typing import Optional

from google.cloud import tasks_v2


def create_http_task_with_token(
    project: str,
    location: str,
    queue: str,
    url: str,
    payload: bytes,
    service_account_email: str,
    audience: Optional[str] = None,
) -> tasks_v2.Task:
    """Create an HTTP POST task with an OIDC token and an arbitrary payload.
    Args:
        project: The project ID where the queue is located.
        location: The location where the queue is located.
        queue: The ID of the queue to add the task to.
        url: The target URL of the task.
        payload: The payload to send.
        service_account_email: The service account to use for generating the OIDC token.
        audience: Audience to use when generating the OIDC token.
    Returns:
        The newly created task.
    """

    # Create a client.
    client = tasks_v2.CloudTasksClient()

    # Construct the request body.
    task = tasks_v2.Task(
        http_request=tasks_v2.HttpRequest(
            http_method=tasks_v2.HttpMethod.POST,
            url=url,
            oidc_token=tasks_v2.OidcToken(
                service_account_email=service_account_email,
                audience=audience,
            ),
            body=payload,
        ),
    )

    # Use the client to build and send the task.
    return client.create_task(
        tasks_v2.CreateTaskRequest(
            parent=client.queue_path(project, location, queue),
            task=task,
        )
    )

Beachten Sie die Datei requirements.txt:

google-cloud-tasks==2.13.1

Java

import com.google.cloud.tasks.v2.CloudTasksClient;
import com.google.cloud.tasks.v2.HttpMethod;
import com.google.cloud.tasks.v2.HttpRequest;
import com.google.cloud.tasks.v2.OidcToken;
import com.google.cloud.tasks.v2.QueueName;
import com.google.cloud.tasks.v2.Task;
import com.google.protobuf.ByteString;
import java.io.IOException;
import java.nio.charset.Charset;

public class CreateHttpTaskWithToken {

  public static void main(String[] args) throws IOException {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "my-project-id";
    String locationId = "us-central1";
    String queueId = "my-queue";
    String serviceAccountEmail =
        "java-docs-samples-testing@java-docs-samples-testing.iam.gserviceaccount.com";
    createTask(projectId, locationId, queueId, serviceAccountEmail);
  }

  // Create a task with a HTTP target and authorization token using the Cloud Tasks client.
  public static void createTask(
      String projectId, String locationId, String queueId, String serviceAccountEmail)
      throws IOException {

    // Instantiates a client.
    try (CloudTasksClient client = CloudTasksClient.create()) {
      String url =
          "https://example.com/taskhandler"; // The full url path that the request will be sent to
      String payload = "Hello, World!"; // The task HTTP request body

      // Construct the fully qualified queue name.
      String queuePath = QueueName.of(projectId, locationId, queueId).toString();

      // Add your service account email to construct the OIDC token.
      // in order to add an authentication header to the request.
      OidcToken.Builder oidcTokenBuilder =
          OidcToken.newBuilder().setServiceAccountEmail(serviceAccountEmail);

      // Construct the task body.
      Task.Builder taskBuilder =
          Task.newBuilder()
              .setHttpRequest(
                  HttpRequest.newBuilder()
                      .setBody(ByteString.copyFrom(payload, Charset.defaultCharset()))
                      .setHttpMethod(HttpMethod.POST)
                      .setUrl(url)
                      .setOidcToken(oidcTokenBuilder)
                      .build());

      // Send create task request.
      Task task = client.createTask(queuePath, taskBuilder.build());
      System.out.println("Task created: " + task.getName());
    }
  }
}

Beachten Sie die Datei pom.xml:

<?xml version='1.0' encoding='UTF-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example.tasks</groupId>
  <artifactId>cloudtasks-snippets</artifactId>
  <packaging>jar</packaging>
  <name>Google Cloud Tasks Snippets</name>

  <!--
    The parent pom defines common style checks and testing strategies for our samples.
    Removing or replacing it should not affect the execution of the samples in anyway.
  -->
  <parent>
    <groupId>com.google.cloud.samples</groupId>
    <artifactId>shared-configuration</artifactId>
    <version>1.2.0</version>
  </parent>

  <properties>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>


  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.google.cloud</groupId>
        <artifactId>libraries-bom</artifactId>
        <version>26.32.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-tasks</artifactId>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.google.truth</groupId>
      <artifactId>truth</artifactId>
      <version>1.4.0</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

Go

import (
	"context"
	"fmt"

	cloudtasks "cloud.google.com/go/cloudtasks/apiv2"
	taskspb "cloud.google.com/go/cloudtasks/apiv2/cloudtaskspb"
)

// createHTTPTaskWithToken constructs a task with a authorization token
// and HTTP target then adds it to a Queue.
func createHTTPTaskWithToken(projectID, locationID, queueID, url, email, message string) (*taskspb.Task, error) {
	// Create a new Cloud Tasks client instance.
	// See https://godoc.org/cloud.google.com/go/cloudtasks/apiv2
	ctx := context.Background()
	client, err := cloudtasks.NewClient(ctx)
	if err != nil {
		return nil, fmt.Errorf("NewClient: %w", err)
	}
	defer client.Close()

	// Build the Task queue path.
	queuePath := fmt.Sprintf("projects/%s/locations/%s/queues/%s", projectID, locationID, queueID)

	// Build the Task payload.
	// https://godoc.org/google.golang.org/genproto/googleapis/cloud/tasks/v2#CreateTaskRequest
	req := &taskspb.CreateTaskRequest{
		Parent: queuePath,
		Task: &taskspb.Task{
			// https://godoc.org/google.golang.org/genproto/googleapis/cloud/tasks/v2#HttpRequest
			MessageType: &taskspb.Task_HttpRequest{
				HttpRequest: &taskspb.HttpRequest{
					HttpMethod: taskspb.HttpMethod_POST,
					Url:        url,
					AuthorizationHeader: &taskspb.HttpRequest_OidcToken{
						OidcToken: &taskspb.OidcToken{
							ServiceAccountEmail: email,
						},
					},
				},
			},
		},
	}

	// Add a payload message if one is present.
	req.Task.GetHttpRequest().Body = []byte(message)

	createdTask, err := client.CreateTask(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("cloudtasks.CreateTask: %w", err)
	}

	return createdTask, nil
}

Node.js

// Imports the Google Cloud Tasks library.
const {CloudTasksClient} = require('@google-cloud/tasks');

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

async function createHttpTaskWithToken() {
  // TODO(developer): Uncomment these lines and replace with your values.
  // const project = 'my-project-id';
  // const queue = 'my-queue';
  // const location = 'us-central1';
  // const url = 'https://example.com/taskhandler';
  // const serviceAccountEmail = 'client@<project-id>.iam.gserviceaccount.com';
  // const payload = 'Hello, World!';

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

  const task = {
    httpRequest: {
      headers: {
        'Content-Type': 'text/plain', // Set content type to ensure compatibility your application's request parsing
      },
      httpMethod: 'POST',
      url,
      oidcToken: {
        serviceAccountEmail,
      },
    },
  };

  if (payload) {
    task.httpRequest.body = Buffer.from(payload).toString('base64');
  }

  console.log('Sending task:');
  console.log(task);
  // Send create task request.
  const request = {parent: parent, task: task};
  const [response] = await client.createTask(request);
  const name = response.name;
  console.log(`Created task ${name}`);
}
createHttpTaskWithToken();

Beachten Sie die Datei package.json:

{
  "name": "appengine-cloudtasks",
  "description": "Google App Engine Cloud Tasks example.",
  "license": "Apache-2.0",
  "author": "Google Inc.",
  "private": true,
  "engines": {
    "node": ">=16.0.0"
  },
  "files": [
    "*.js"
  ],
  "scripts": {
    "test": "c8 mocha -p -j 2 --timeout 30000",
    "start": "node server.js"
  },
  "dependencies": {
    "@google-cloud/tasks": "^5.0.0",
    "express": "^4.16.3"
  },
  "devDependencies": {
    "c8": "^10.0.0",
    "chai": "^4.5.0",
    "mocha": "^10.0.0",
    "uuid": "^10.0.0"
  }
}

Nächste Schritte