Esecuzione di attività asincrone

Mantieni tutto organizzato con le raccolte Salva e classifica i contenuti in base alle tue preferenze.

Puoi utilizzare Cloud Tasks per accodare in modo sicuro un'attività da elaborare in modo asincrono da un servizio Cloud Run. I casi d'uso tipici includono:

  • Preservare le richieste tramite incidenti di produzione imprevisti
  • Regolazione dei picchi di traffico ritardando il lavoro non rivolto all'utente
  • Aumentare i tempi di risposta degli utenti delegando le operazioni in background lente che devono essere gestite da un altro servizio, ad esempio gli aggiornamenti del database o l'elaborazione batch
  • Limitazione della frequenza di chiamata ai servizi di backup come database e API di terze parti

Questa pagina mostra come accodare le attività di cui viene eseguito il push in modo sicuro tramite il protocollo HTTPS in un servizio Cloud Run privato. Descrive il comportamento richiesto per il servizio Cloud Run privato, le autorizzazioni necessarie per l'account di servizio, la creazione di attività in coda e la creazione di attività.

Prima di iniziare

Abilita l'API Cloud Tasks per il progetto in uso.

Deployment di un servizio Cloud Run per gestire le attività

Per eseguire il deployment di un servizio che accetta attività inviate alla coda delle attività, esegui il deployment del servizio come faresti per qualsiasi altro servizio Cloud Run. Il servizio Cloud Run deve restituire un codice HTTP 200 per confermare l'esito positivo dell'elaborazione dell'attività.

Le attività verranno trasferite a questo servizio Cloud Run come richieste HTTPS da Cloud Tasks.

La risposta a Cloud Tasks deve avvenire entro il timeout configurato. Per i carichi di lavoro che devono essere eseguiti più a lungo del timeout di Cloud Tasks massimo, valuta la possibilità di utilizzare i job Cloud Run.

Deployment con Terraform

Per creare un servizio, aggiungi quanto segue al file .tf:

resource "google_cloud_run_service" "default" {
    name     = "cloud-run-service-name"
    location = "us-central1"
    provider = google-beta
    template {
      spec {
            containers {
                image = "gcr.io/cloudrun/hello"
            }
      }
    }
    traffic {
      percent         = 100
      latest_revision = true
    }
}

Per applicare la configurazione Terraform in un progetto Google Cloud, completa i passaggi seguenti:

  1. Avvia Cloud Shell.
  2. Imposta il progetto Google Cloud a cui vuoi applicare la configurazione Terraform:
    export GOOGLE_CLOUD_PROJECT=PROJECT_ID
    
  3. Crea una directory e apri un nuovo file al suo interno. Il nome file deve avere l'estensione .tf, ad esempio main.tf:
    mkdir DIRECTORY && cd DIRECTORY && nano main.tf
    
  4. Copia l'esempio in main.tf.
  5. Esamina e modifica i parametri di esempio da applicare al tuo ambiente.
  6. Salva le modifiche premendo Ctrl-x, quindi y.
  7. Inizializza Terraform:
    terraform init
  8. Rivedi la configurazione e verifica che le risorse che Terraform creerà o aggiornerà corrispondano alle tue aspettative:
    terraform plan

    Apporta le correzioni necessarie alla configurazione.

  9. Applica la configurazione Terraform eseguendo il comando seguente e inserendo yes nel prompt:
    terraform apply

    Attendi finché Terraform non visualizza il messaggio "Applica completato".

  10. Apri il progetto Google Cloud per visualizzare i risultati. Nella console Google Cloud, vai alle tue risorse nell'interfaccia utente per assicurarti che Terraform le abbia create o aggiornate.

Creazione di una coda di attività

Riga di comando

Per creare una coda di attività, utilizza il comando

gcloud tasks queues create QUEUE-ID

sostituendo QUEUE-ID con il nome che vuoi assegnare alla coda delle attività: deve essere univoco nel progetto. Se ti viene chiesto di creare un'app App Engine nel tuo progetto, rispondi y per crearla. Cloud Tasks lo utilizza per la coda: assicurati di scegliere la stessa località che utilizzi per il servizio Cloud Run.

Nella maggior parte dei casi, la configurazione predefinita della coda delle attività dovrebbe funzionare. Tuttavia, se vuoi, puoi impostare limiti di frequenza e parametri di ripetizione diversi.

Terraform

Per creare una coda di attività, aggiungi quanto segue al file .tf:

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

Applica le modifiche inserendo terraform apply.

Creazione di un account di servizio da associare alle attività

Devi creare un account di servizio che verrà associato alle attività accodate. Questo account di servizio deve avere il ruolo IAM Invoker di Cloud Run per consentire alla coda delle attività di eseguire il push delle attività al servizio Cloud Run. .

Console

  1. In Google Cloud Console, vai alla pagina Account di servizio.

    Vai agli account di servizio

  2. Seleziona un progetto.

  3. Inserisci il nome di un account di servizio da visualizzare in Google Cloud Console.

    Google Cloud Console genera un ID account di servizio in base a questo nome. Modifica l'ID, se necessario. Non potrai modificare l'ID in un secondo momento.

  4. (Facoltativo) Inserisci una descrizione dell'account di servizio.

  5. Fai clic su Crea.

  6. Fai clic sul campo Seleziona un ruolo.

  7. In Tutti i ruoli, seleziona Cloud Run > Invoker di Cloud Run.

  8. Fai clic su Fine.

Riga di comando

  1. Crea l'account di servizio:

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

    Sostituisci

    • SERVICE_ACCOUNT_NAME con un nome in lettere minuscole univoco all'interno del progetto Google Cloud, ad esempio my-invoker-service-account-name.
    • DISPLAYED_SERVICE_ACCOUNT_NAME con il nome che vuoi visualizzare per questo account di servizio, ad esempio nella console, ad esempio My Invoker Service Account.
  2. Per Cloud Run, concedi al tuo account di servizio l'autorizzazione per richiamare il tuo servizio:

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

    Sostituisci

    • SERVICE con il nome del servizio che vuoi richiamare da Cloud Tasks.
    • SERVICE_ACCOUNT_NAME con il nome dell'account di servizio.
    • PROJECT_ID con il tuo ID progetto Google Cloud.

Terraform

Aggiungi quanto segue al tuo file .tf:

Crea l'account di servizio:

resource "google_service_account" "sa" {
  account_id   = "cloud-run-task-invoker"
  display_name = "Cloud Run Task Invoker"
  provider = google-beta
}

Per Cloud Run, concedi al tuo account di servizio l'autorizzazione per richiamare il servizio:

resource "google_cloud_run_service_iam_binding" "binding" {
  location = google_cloud_run_service.default.location
  service = google_cloud_run_service.default.name
  role = "roles/run.invoker"
  members = ["serviceAccount:${google_service_account.sa.email}"]
  provider = google-beta
  project = google_cloud_run_service.default.project
}

Applica le modifiche inserendo terraform apply.

Creare attività HTTP con token di autenticazione

Quando crei un'attività da inviare alla coda delle attività, devi specificare il progetto, la posizione, il nome della coda, l'email dell'account di servizio creato in precedenza da associare alle attività, l'URL del servizio Cloud Run privato che eseguirà l'attività e tutti gli altri dati che devi inviare. Puoi scegliere di impostare questi valori come hardcoded, anche se i valori come l'ID progetto, la località e l'indirizzo email dell'account di servizio possono essere recuperati in modo dinamico dal server di metadati Cloud Run.

Fai riferimento alla documentazione dell'API Cloud Tasks per i dettagli del corpo della richiesta di attività. Tieni presente che le richieste che contengono payload di dati devono utilizzare il metodo HTTP PUT o POST.

Per farlo, il codice che accoda le attività deve disporre delle autorizzazioni IAM necessarie, come il ruolo Cloud Enqueuer. Il codice avrà le autorizzazioni IAM necessarie se utilizzi l'account di servizio predefinito su Cloud Run.

Gli esempi seguenti creano richieste di attività che includono anche la creazione di un token di intestazione. Negli esempi vengono utilizzati i token OIDC. Per utilizzare un token OAuth, sostituisci il parametro OIDC con il parametro OAuth appropriato per il linguaggio durante la creazione della richiesta.

Python

"""Create a task for a given queue with an arbitrary payload."""

from google.cloud import tasks_v2

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

# TODO(developer): Uncomment these lines and replace with your values.
# project = 'my-project-id'
# queue = 'my-queue'
# location = 'us-central1'
# url = 'https://example.com/task_handler?param=value'
# audience = 'https://example.com/task_handler'
# service_account_email = 'service-account@my-project-id.iam.gserviceaccount.com';
# payload = 'hello'

# Construct the fully qualified queue name.
parent = client.queue_path(project, location, queue)

# Construct the request body.
task = {
    "http_request": {  # Specify the type of request.
        "http_method": tasks_v2.HttpMethod.POST,
        "url": url,  # The full url path that the task will be sent to.
        "oidc_token": {
            "service_account_email": service_account_email,
            "audience": audience,
        },
    }
}

if payload is not None:
    # The API expects a payload of type bytes.
    converted_payload = payload.encode()

    # Add the payload to the request.
    task["http_request"]["body"] = converted_payload

# Use the client to build and send the task.
response = client.create_task(request={"parent": parent, "task": task})

print("Created task {}".format(response.name))
return response

Prendi nota del file requirements.txt:

google-cloud-tasks==2.10.2

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());
    }
  }
}

Prendi nota del file 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.google.cloud</groupId>
  <artifactId>cloudtasks-snippets</artifactId>
  <packaging>jar</packaging>
  <name>Google Cloud Tasks Snippets</name>
  <url>https://github.com/googleapis/java-tasks</url>

  <!--
    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.1.2</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.1.3</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

Go

import (
	"context"
	"fmt"

	cloudtasks "cloud.google.com/go/cloudtasks/apiv2"
	taskspb "google.golang.org/genproto/googleapis/cloud/tasks/v2"
)

// 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: %v", 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: %v", 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',
      },
      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();

Prendi nota del file package.json:

{
  "name": "appengine-cloudtasks",
  "description": "Google App Engine Cloud Tasks example.",
  "license": "Apache-2.0",
  "author": "Google Inc.",
  "private": true,
  "engines": {
    "node": ">=12.0.0"
  },
  "files": [
    "*.js"
  ],
  "scripts": {
    "test": "mocha",
    "start": "node server.js"
  },
  "dependencies": {
    "@google-cloud/tasks": "^3.0.4",
    "body-parser": "^1.18.3",
    "express": "^4.16.3"
  },
  "devDependencies": {
    "chai": "^4.2.0",
    "mocha": "^8.0.0",
    "uuid": "^9.0.0"
  }
}

Passaggi successivi