建立 HTTP 目標工作

Cloud Tasks 處理常式可以在任何具備外部 IP 位址的 HTTP 端點上執行,例如 GKECompute Engine,甚至是內部部署的網路伺服器。您的工作可以在上述任一服務中以可靠且可供設定的方式執行。

本頁面說明如何透過程式建立基本 HTTP 目標工作,並排入 Cloud Tasks 佇列

對於具有 HTTP 目標的工作 (相較於較不常見的明確 App Engine 目標),建立工作的方式有兩種:

  • CreateTask 方法:您必須明確建立工作物件。如果佇列中的工作有不同的路徑設定,請使用這個方法。在這種情況下,您可以在工作層級指定路徑,但無法使用佇列層級路徑。這種做法會使用 CreateTask 方法。

  • BufferTask 方法:如果佇列設定為在服務前緩衝處理工作,請使用這個方法。佇列必須具備佇列層級的路由。 這種做法會使用 BufferTask 方法。

使用 CreateTask 方法建立工作

本節將說明如何建構工作物件來建立工作。使用 CreateTask 方法。

使用 CreateTask 方法建立工作時,您會明確建立及定義工作物件。您必須指定用於處理工作的服務和處理常式。

您也可以選擇將工作專屬資料傳送到處理常式。也可以微調工作的設定,例如安排未來的執行時間,或限制工作失敗時的重試次數 (請參閱「進階設定」)。

下列範例會呼叫 CreateTask 方法,使用 Cloud Tasks 用戶端程式庫建立工作。

C#


using Google.Cloud.Tasks.V2;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using System;

class CreateHttpTask
{
    public string CreateTask(
        string projectId = "YOUR-PROJECT-ID",
        string location = "us-central1",
        string queue = "my-queue",
        string url = "http://example.com/taskhandler",
        string payload = "Hello World!",
        int inSeconds = 0)
    {
        CloudTasksClient client = CloudTasksClient.Create();
        QueueName parent = new QueueName(projectId, location, queue);

        var response = client.CreateTask(new CreateTaskRequest
        {
            Parent = parent.ToString(),
            Task = new Task
            {
                HttpRequest = new HttpRequest
                {
                    HttpMethod = HttpMethod.Post,
                    Url = url,
                    Body = ByteString.CopyFromUtf8(payload)
                },
                ScheduleTime = Timestamp.FromDateTime(
                    DateTime.UtcNow.AddSeconds(inSeconds))
            }
        });

        Console.WriteLine($"Created Task {response.Name}");
        return response.Name;
    }
}

Go


// Command createHTTPtask constructs and adds a task to a Cloud Tasks Queue.
package main

import (
	"context"
	"fmt"

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

// createHTTPTask creates a new task with a HTTP target then adds it to a Queue.
func createHTTPTask(projectID, locationID, queueID, url, 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,
				},
			},
		},
	}

	// 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
}

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.QueueName;
import com.google.cloud.tasks.v2.Task;
import com.google.protobuf.ByteString;
import java.io.IOException;
import java.nio.charset.Charset;

public class CreateHttpTask {

  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";
    createTask(projectId, locationId, queueId);
  }

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

    // Instantiates a client.
    try (CloudTasksClient client = CloudTasksClient.create()) {
      String url = "https://example.com/taskhandler";
      String payload = "Hello, World!";

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

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

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

請注意 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>

Node.js

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

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

async function createHttpTask() {
  // 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 payload = 'Hello, World!';
  // const inSeconds = 180;

  // 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,
    },
  };

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

  if (inSeconds) {
    // The time when the task is scheduled to be attempted.
    task.scheduleTime = {
      seconds: parseInt(inSeconds) + Date.now() / 1000,
    };
  }

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

請注意 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"
  }
}

PHP

use Google\Cloud\Tasks\V2\Client\CloudTasksClient;
use Google\Cloud\Tasks\V2\CreateTaskRequest;
use Google\Cloud\Tasks\V2\HttpMethod;
use Google\Cloud\Tasks\V2\HttpRequest;
use Google\Cloud\Tasks\V2\Task;

/** Uncomment and populate these variables in your code */
// $projectId = 'The Google project ID';
// $locationId = 'The Location ID';
// $queueId = 'The Cloud Tasks Queue ID';
// $url = 'The full url path that the task request will be sent to.'
// $payload = 'The payload your task should carry to the task handler. Optional';

// Instantiate the client and queue name.
$client = new CloudTasksClient();
$queueName = $client->queueName($projectId, $locationId, $queueId);

// Create an Http Request Object.
$httpRequest = new HttpRequest();
// The full url path that the task request will be sent to.
$httpRequest->setUrl($url);
// POST is the default HTTP method, but any HTTP method can be used.
$httpRequest->setHttpMethod(HttpMethod::POST);
// Setting a body value is only compatible with HTTP POST and PUT requests.
if (!empty($payload)) {
    $httpRequest->setBody($payload);
}

// Create a Cloud Task object.
$task = new Task();
$task->setHttpRequest($httpRequest);

// Send request and print the task name.
$request = (new CreateTaskRequest())
    ->setParent($queueName)
    ->setTask($task);
$response = $client->createTask($request);
printf('Created task %s' . PHP_EOL, $response->getName());

請注意 composer.json 檔案:

{
    "require": {
        "google/cloud-tasks": "^2.0"
    }
}

Python

import datetime
import json
from typing import Dict, Optional

from google.cloud import tasks_v2
from google.protobuf import duration_pb2, timestamp_pb2


def create_http_task(
    project: str,
    location: str,
    queue: str,
    url: str,
    json_payload: Dict,
    scheduled_seconds_from_now: Optional[int] = None,
    task_id: Optional[str] = None,
    deadline_in_seconds: Optional[int] = None,
) -> tasks_v2.Task:
    """Create an HTTP POST task with a JSON 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.
        json_payload: The JSON payload to send.
        scheduled_seconds_from_now: Seconds from now to schedule the task for.
        task_id: ID to use for the newly created task.
        deadline_in_seconds: The deadline in seconds for task.
    Returns:
        The newly created task.
    """

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

    # Construct the task.
    task = tasks_v2.Task(
        http_request=tasks_v2.HttpRequest(
            http_method=tasks_v2.HttpMethod.POST,
            url=url,
            headers={"Content-type": "application/json"},
            body=json.dumps(json_payload).encode(),
        ),
        name=(
            client.task_path(project, location, queue, task_id)
            if task_id is not None
            else None
        ),
    )

    # Convert "seconds from now" to an absolute Protobuf Timestamp
    if scheduled_seconds_from_now is not None:
        timestamp = timestamp_pb2.Timestamp()
        timestamp.FromDatetime(
            datetime.datetime.utcnow()
            + datetime.timedelta(seconds=scheduled_seconds_from_now)
        )
        task.schedule_time = timestamp

    # Convert "deadline in seconds" to a Protobuf Duration
    if deadline_in_seconds is not None:
        duration = duration_pb2.Duration()
        duration.FromSeconds(deadline_in_seconds)
        task.dispatch_deadline = duration

    # Use the client to send a CreateTaskRequest.
    return client.create_task(
        tasks_v2.CreateTaskRequest(
            # The queue to add the task to
            parent=client.queue_path(project, location, queue),
            # The task itself
            task=task,
        )
    )

請注意 requirements.txt 檔案:

google-cloud-tasks==2.18.0

Ruby

require "google/cloud/tasks"

# Create a Task with an HTTP Target
#
# @param [String] project_id Your Google Cloud Project ID.
# @param [String] location_id Your Google Cloud Project Location ID.
# @param [String] queue_id Your Google Cloud Tasks Queue ID.
# @param [String] url The full path to sent the task request to.
# @param [String] payload The request body of your task.
# @param [Integer] seconds The delay, in seconds, to process your task.
def create_http_task project_id, location_id, queue_id, url, payload: nil, seconds: nil
  # Instantiates a client.
  client = Google::Cloud::Tasks.cloud_tasks

  # Construct the fully qualified queue name.
  parent = client.queue_path project: project_id, location: location_id, queue: queue_id

  # Construct task.
  task = {
    http_request: {
      http_method: "POST",
      url:         url
    }
  }

  # Add payload to task body.
  task[:http_request][:body] = payload if payload

  # Add scheduled time to task.
  if seconds
    timestamp = Google::Protobuf::Timestamp.new
    timestamp.seconds = Time.now.to_i + seconds.to_i
    task[:schedule_time] = timestamp
  end

  # Send create task request.
  puts "Sending task #{task}"

  response = client.create_task parent: parent, task: task

  puts "Created task #{response.name}" if response.name
end

使用 BufferTask 方法建立工作

本節將說明如何透過傳送 HTTP 要求建立工作。您使用的方法稱為 BufferTask

限制

BufferTask 方法有下列限制:

  • 用戶端程式庫:用戶端程式庫不支援 BufferTask 方法。

  • RPC API:RPC API 不支援 BufferTask 方法。

  • 工作層級的路由:這個方法不支援工作層級的路由。由於以這種方式建立工作時無法新增轉送資訊,因此您必須使用佇列層級轉送 (否則工作不會有轉送資訊)。如果佇列尚未使用佇列層級的路由,請參閱「為 HTTP 工作設定佇列層級的路由」。

呼叫 BufferTask 方法

以下範例說明如何將 HTTP POST 要求傳送至 Cloud Tasks API buffer 端點,藉此建立工作。

curl

下列程式碼片段範例說明如何使用 curlBufferTask 方法建立工作:

curl -X HTTP_METHOD\
"https://cloudtasks.googleapis.com/v2/projects/PROJECT_ID/locations/LOCATION/queues/QUEUE_ID/tasks:buffer" \

更改下列內容:

  • HTTP_METHOD:要求的 HTTP 方法,例如 GETPOST
  • PROJECT_ID:您的 Google Cloud 專案 ID。 如要取得這項資訊,請在終端機中執行下列指令:
    gcloud config get-value project
  • LOCATION:佇列的位置。
  • QUEUE_ID:佇列的 ID。

Python

from google.cloud import tasks_v2beta3 as tasks

import requests


def send_task_to_http_queue(
    queue: tasks.Queue, body: str = "", token: str = "", headers: dict = {}
) -> int:
    """Send a task to an HTTP queue.
    Args:
        queue: The queue to send task to.
        body: The body of the task.
        auth_token: An authorization token for the queue.
        headers: Headers to set on the task.
    Returns:
        The matching queue, or None if it doesn't exist.
    """

    # Use application default credentials if not supplied in a header
    if token:
        headers["Authorization"] = f"Bearer {token}"

    endpoint = f"https://cloudtasks.googleapis.com/v2beta3/{queue.name}/tasks:buffer"
    response = requests.post(endpoint, body, headers=headers)

    return response.status_code

設定服務帳戶以驗證 HTTP 目標處理常式

如果您有具備存取處理常式適當憑證的服務帳戶,Cloud Tasks 即可呼叫需要驗證的 HTTP 目標處理常式。

只要授予適當角色,您就能使用目前的服務帳戶。 這些操作說明涵蓋專為這項功能建立新服務帳戶的步驟。用於 Cloud Tasks 驗證的現有或新服務帳戶必須與 Cloud Tasks 佇列位於同一個專案。

  1. 前往 Google Cloud 控制台的「Service Accounts」(服務帳戶) 頁面。

    前往「Service Accounts」(服務帳戶)

  2. 如有必要,請選取適當的專案。

  3. 按一下「建立服務帳戶」

  4. 在「Service account details」(服務帳戶詳細資料) 部分中,為帳戶命名。控制台會為帳戶建立相關的電子郵件帳戶名稱。這是指您參照帳戶的方式。你也可以新增帳戶用途的說明。按一下「建立並繼續」

  5. 在「將專案存取權授予這個服務帳戶」部分,按一下「選取角色」。搜尋並選取「Cloud Tasks 排入佇列者」。 這個角色可讓服務帳戶將工作新增至佇列。

  6. 按一下 [+ Add another role] (+ 新增其他角色)

  7. 按一下「選擇角色」。搜尋並選取「服務帳戶使用者」。這個角色可讓服務帳戶使用服務帳戶憑證,授權佇列代表自己建立符記。

  8. 如果您的處理常式為 Google Cloud的一部分,請授予服務帳戶與存取處理常式執行所在服務相關聯的角色。 Google Cloud 中的每項服務都需要不同的角色。舉例來說,如要存取 Cloud Run 上的處理常式,請授予「Cloud Run 叫用者」角色。您可以使用剛建立的服務帳戶,或專案中的任何其他服務帳戶。

  9. 按一下「Done」(完成),即完成建立服務帳戶。

Cloud Tasks 本身必須具備自己的服務帳戶,且該帳戶須被授予 Cloud Tasks Service Agent 角色,這樣才能根據與 Cloud Tasks 服務帳戶相關聯的憑證產生標頭權杖,藉此對處理常式目標進行驗證。當您啟用 Cloud Tasks API 時,系統會自動建立 Cloud Tasks 服務帳戶並授予此角色,「但」如果您在 2019 年 3 月 19 日之前啟用,則必須手動新增角色

使用具備驗證憑證的 HTTP 目標工作

如要在 Cloud Tasks 和需要驗證的 HTTP 目標處理常式之間進行驗證,Cloud Tasks 會建立標頭憑證。這個權杖是以Cloud Tasks Enqueuer服務帳戶中的憑證為依據,並以電子郵件地址識別。用於驗證的服務帳戶必須與 Cloud Tasks 佇列位於同一專案。佇列會透過 HTTPS 將要求連同標頭權杖傳送至處理常式。您可以使用ID 權杖存取權杖。 一般來說,在 Google Cloud上執行的任何處理常式都應使用 ID 權杖,例如在 Cloud Run 函式或 Cloud Run 上。主要例外狀況是 *.googleapis.com 上託管的 Google API,這些 API 預期會使用存取權杖。

您可以在佇列層級或工作層級設定驗證。如要在佇列層級設定驗證,請參閱「建立 Cloud Tasks 佇列」。如果在佇列層級設定驗證,這項設定會覆寫工作層級的設定。如要在工作層級設定驗證,請在工作本身指定ID (OIDC) 權杖存取 (OAuth) 權杖

CreateTask 方法

下列範例會使用 Cloud Tasks 用戶端程式庫的 CreateTask 方法建立工作,其中包含標頭權杖的建立。這些範例會使用 ID 權杖。 如要使用存取權杖,請在建構要求時,將 OIDC 參數替換為適當的 OAuth 參數語言。

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
}

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

請注意 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>

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

請注意 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"
  }
}

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,
        )
    )

請注意 requirements.txt 檔案:

google-cloud-tasks==2.18.0

BufferTask 方法

下列範例使用應用程式預設憑證,在透過 BufferTask 方法建立工作時進行驗證。

curl

curl -X HTTP_METHOD\
"https://cloudtasks.googleapis.com/v2/projects/PROJECT_ID/locations/LOCATION/queues/QUEUE_ID/tasks:buffer" \
    -H "Authorization: Bearer ACCESS_TOKEN"

更改下列內容:

  • HTTP_METHOD:要求的 HTTP 方法,例如 GETPOST
  • PROJECT_ID:您的 Google Cloud 專案 ID。 如要取得這項資訊,請在終端機中執行下列指令:
    gcloud config get-value project
  • LOCATION:佇列的位置。
  • QUEUE_ID:佇列的 ID。
  • ACCESS_TOKEN:您的存取權杖。如要取得這項資訊,請在終端機中執行下列指令:
  • gcloud auth application-default login
  • gcloud auth application-default print-access-token

Python

在下列程式碼範例中,提供您的驗證權杖值。

from google.cloud import tasks_v2beta3 as tasks

import requests


def send_task_to_http_queue(
    queue: tasks.Queue, body: str = "", token: str = "", headers: dict = {}
) -> int:
    """Send a task to an HTTP queue.
    Args:
        queue: The queue to send task to.
        body: The body of the task.
        auth_token: An authorization token for the queue.
        headers: Headers to set on the task.
    Returns:
        The matching queue, or None if it doesn't exist.
    """

    # Use application default credentials if not supplied in a header
    if token:
        headers["Authorization"] = f"Bearer {token}"

    endpoint = f"https://cloudtasks.googleapis.com/v2beta3/{queue.name}/tasks:buffer"
    response = requests.post(endpoint, body, headers=headers)

    return response.status_code

自行提供 HTTP 目標工作處理常式

HTTP 目標工作處理常式與 App Engine 工作處理常式非常類似,除了:

  • 逾時:針對所有 HTTP 目標工作處理常式,預設逾時為 10 分鐘,最多為 30 分鐘。
  • 驗證邏輯:如要透過在目標服務中寫入自有的程式碼來驗證憑證,您應使用 ID 憑證。如要進一步瞭解相關必要內容,請參閱 OpenID Connect,尤其是驗證 ID 權杖一節。
  • 標頭:HTTP 目標要求會設定佇列標頭,其中包含處理常式可使用的工作專屬資訊。這些標頭與App Engine 工作要求中設定的標頭類似,但並不相同。這些標頭提供資訊,請勿將這些 ID 做為身分來源。

    如果外部使用者對您應用程式發出的要求中出現這些標頭,則系統會更換為內部標頭。但如果要求來自於已登入應用程式的系統管理員,則屬唯一例外情況,系統允許管理員設定標頭以進行測試。

    HTTP 目標要求一律包含下列標頭:

    標頭 說明
    X-CloudTasks-QueueName 佇列名稱。
    X-CloudTasks-TaskName 工作的「簡短」名稱;如果在建立工作時沒有指定名稱,則是由系統產生的唯一 ID 來代替。這是完整工作名稱中的 my-task-id 值,也就是 task_name = projects/my-project-id/locations/my-location/queues/my-queue-id/tasks/my-task-id
    X-CloudTasks-TaskRetryCount 這個工作的已重試次數。若為第一次嘗試,此值為 0。這個數字會將工作因 5XX 錯誤代碼,所以從未達到執行階段而失敗的次數計算在內。
    X-CloudTasks-TaskExecutionCount 工作收到處理常式回應的總次數。由於 Cloud Tasks 在收到成功回應後會刪除工作,所以先前的所有處理常式回應都是失敗。這個數字不包括因 5XX 錯誤碼而失敗的次數。
    X-CloudTasks-TaskETA 工作的排程時間,從 1970 年 1 月 1 日算起並以秒數表示。

    此外,Cloud Tasks 發出的要求還可能包含下列標頭:

    標頭 說明
    X-CloudTasks-TaskPreviousResponse 來自上次重試的 HTTP 回應碼。
    X-CloudTasks-TaskRetryReason 重試工作的原因。

手動新增 Cloud Tasks 服務代理人角色

您可以手動將 Cloud Tasks 服務代理人 (roles/cloudtasks.serviceAgent) 角色新增至 Cloud Tasks 服務帳戶,該帳戶是 Cloud Tasks 的主要服務代理人

如果您是在 2019 年 3 月 19 日之前啟用 Cloud Tasks API,才需要執行此操作。

主控台

  1. 在控制台的「歡迎」 Google Cloud 頁面中,找出並複製專案的專案編號。 Google Cloud
  2. 前往 Google Cloud 控制台的「IAM」頁面。

    前往「身分與存取權管理」頁面

  3. 按一下「Grant access」(授予存取權)。「授予存取權」窗格隨即開啟。

  4. 在「新增主體」部分,新增格式如下的電子郵件地址:

     service-PROJECT_NUMBER@gcp-sa-cloudtasks.iam.gserviceaccount.com
     

    PROJECT_NUMBER 替換為您的 Google Cloud 專案編號。

  5. 在「指派角色」部分,搜尋並選取「Cloud Tasks Service Agent」

  6. 按一下 [儲存]

gcloud

  1. 找出專案編號:

    gcloud projects describe PROJECT_ID --format='table(projectNumber)'

    PROJECT_ID 替換為您的專案 ID。

  2. 複製編號。

  3. 使用您複製的專案編號,授予 Cloud Tasks 服務帳戶 Cloud Tasks Service Agent 角色:

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:service-PROJECT_NUMBER@gcp-sa-cloudtasks.iam.gserviceaccount.com \
        --role roles/cloudtasks.serviceAgent

    更改下列內容:

    • PROJECT_ID:您的 Google Cloud 專案 ID。
    • PROJECT_NUMBER:您的 Google Cloud專案編號。

其他設定

您可以設定多項工作屬性。如需完整清單,請參閱工作資源定義。舉例來說,您可以自訂下列屬性:

  • 命名:如果您選擇指定工作名稱,Cloud Tasks 就能使用該名稱確保工作不會重複,但這項處理作業可能會增加延遲時間。
  • 排程:你可以排定在未來時間執行工作。這項功能僅支援 CreateTask,不支援 BufferTask

您也可以設定佇列屬性,例如路由覆寫、速率限制和重試參數。這些設定會套用至佇列中的所有工作。 詳情請參閱「設定 Cloud Tasks 佇列」。

後續步驟