App Engine 작업 만들기

이 페이지에서는 프로그래매틱 방식으로 App Engine 태스크를 만들어 Cloud Tasks 큐에 배치하는 방법을 설명합니다. 태스크를 처리하는 서비스와 핸들러를 이 절차를 이용하여 명시적으로 지정하고 필요에 따라 태스크별 데이터를 핸들러에 함께 전달할 수 있습니다.

태스크 실행 시간을 예약하거나 태스크가 실패할 경우 재시도할 횟수를 제한하는 등 작업의 구성을 세부적으로 조정할 수도 있습니다. 태스크의 이름을 지정하면 Cloud Tasks에서 이 이름을 사용하여 태스크 중복 삭제를 보장할 수 있지만 필요한 처리로 인해 지연 시간이 늘어날 수 있습니다.

원하는 대로 구성할 수 있는 HTTP 요청 양식으로 태스크를 만듭니다. 그러나 Google Cloud 클라이언트 라이브러리를 사용하면 아래의 예시와 같이 Google 인증 등 서버와의 통신에 대한 하위 수준의 세부정보 관리가 가능합니다.

C#


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

class CreateAppEngineTask
{
    public string CreateTask(
        string projectId = "YOUR-PROJECT-ID",
        string location = "us-central1",
        string queue = "my-queue",
        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
            {
                AppEngineHttpRequest = new AppEngineHttpRequest
                {
                    HttpMethod = HttpMethod.Post,
                    RelativeUri = "/log_payload",
                    Body = ByteString.CopyFromUtf8(payload)
                },
                ScheduleTime = Timestamp.FromDateTime(
                    DateTime.UtcNow.AddSeconds(inSeconds))
            }
        });

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

Python

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

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

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

# TODO(developer): Uncomment these lines and replace with your values.
# project = 'my-project-id'
# queue = 'my-appengine-queue'
# location = 'us-central1'
# payload = 'hello'

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

# Construct the request body.
task = {
        'app_engine_http_request': {  # Specify the type of request.
            'http_method': 'POST',
            'relative_uri': '/example_task_handler'
        }
}
if payload is not None:
    # The API expects a payload of type bytes.
    converted_payload = payload.encode()

    # Add the payload to the request.
    task['app_engine_http_request']['body'] = converted_payload

if in_seconds is not None:
    # Convert "seconds from now" into an rfc3339 datetime string.
    d = datetime.datetime.utcnow() + datetime.timedelta(seconds=in_seconds)

    # Create Timestamp protobuf.
    timestamp = timestamp_pb2.Timestamp()
    timestamp.FromDatetime(d)

    # Add the timestamp to the tasks.
    task['schedule_time'] = timestamp

# Use the client to build and send the task.
response = client.create_task(parent, task)

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

requirements.txt 파일 참고:

Flask==1.1.2
gunicorn==20.0.4
google-cloud-tasks==1.5.0

자바

// Instantiates a client.
try (CloudTasksClient client = CloudTasksClient.create()) {

  // Variables provided by the CLI.
  // projectId = "my-project-id";
  // queueName = "my-appengine-queue";
  // location = "us-central1";
  // payload = "hello";

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

  // Construct the task body.
  Task.Builder taskBuilder =
      Task.newBuilder()
          .setAppEngineHttpRequest(
              AppEngineHttpRequest.newBuilder()
                  .setBody(ByteString.copyFrom(payload, Charset.defaultCharset()))
                  .setRelativeUri("/tasks/create")
                  .setHttpMethod(HttpMethod.POST)
                  .build());

  if (params.hasOption(IN_SECONDS_OPTION.getOpt())) {
    // Add the scheduled time to the request.
    int seconds = Integer.parseInt(params.getOptionValue(IN_SECONDS_OPTION.getOpt()));
    taskBuilder.setScheduleTime(
        Timestamp.newBuilder()
            .setSeconds(Instant.now(Clock.systemUTC()).plusSeconds(seconds).getEpochSecond()));
  }

  // 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"?>
<!--
Copyright 2018 Google LLC

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->
<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>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <groupId>com.example.task</groupId>
  <artifactId>appengine-tasks-j8</artifactId>

  <!--
    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.0.18</version>
    <relativePath></relativePath>
  </parent>

  <properties>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
    <failOnMissingWebXml>false</failOnMissingWebXml>
  </properties>

  <dependencies>
    <!-- Compile/runtime dependencies -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <type>jar</type>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-tasks</artifactId>
      <version>1.30.0</version>
    </dependency>
    <dependency>
      <groupId>commons-cli</groupId>
      <artifactId>commons-cli</artifactId>
      <version>1.4</version>
      <scope>compile</scope>
    </dependency>
    <!-- Test dependencies -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.google.truth</groupId>
      <artifactId>truth</artifactId>
      <version>1.0.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <!-- for hot reload of the web application-->
    <outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes
    </outputDirectory>
    <plugins>
      <plugin>
        <groupId>com.google.cloud.tools</groupId>
        <artifactId>appengine-maven-plugin</artifactId>
        <version>2.3.0</version>
        <configuration>
          <projectId>GCLOUD_CONFIG</projectId>
          <version>GCLOUD_CONFIG</version>
          <deploy.promote>true</deploy.promote>
          <deploy.stopPreviousVersion>true</deploy.stopPreviousVersion>
        </configuration>
      </plugin>

      <!-- <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.3.0</version>
      </plugin> -->

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>3.0.0</version>
        <configuration>
          <mainClass>com.example.task.CreateTask</mainClass>
          <cleanupDaemonThreads>false</cleanupDaemonThreads>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

PHP

use Google\Cloud\Tasks\V2\AppEngineHttpRequest;
use Google\Cloud\Tasks\V2\CloudTasksClient;
use Google\Cloud\Tasks\V2\HttpMethod;
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 App Engine Queue ID';
// $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 App Engine Http Request Object.
$httpRequest = new AppEngineHttpRequest();
// The path of the HTTP request to the App Engine service.
$httpRequest->setRelativeUri('/task_handler');
// 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 (isset($payload)) {
    $httpRequest->setBody($payload);
}

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

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

composer.json 파일 참고

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

Go


// Command create_task constructs and adds a task to an App Engine Queue.
package main

import (
	"context"
	"fmt"

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

// createTask creates a new task in your App Engine queue.
func createTask(projectID, locationID, queueID, 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#AppEngineHttpRequest
			MessageType: &taskspb.Task_AppEngineHttpRequest{
				AppEngineHttpRequest: &taskspb.AppEngineHttpRequest{
					HttpMethod:  taskspb.HttpMethod_POST,
					RelativeUri: "/task_handler",
				},
			},
		},
	}

	// Add a payload message if one is present.
	req.Task.GetAppEngineHttpRequest().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();

// TODO(developer): Uncomment these lines and replace with your values.
// const project = 'my-project-id';
// const queue = 'my-appengine-queue';
// const location = 'us-central1';
// const payload = 'Hello, World!';

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

const task = {
  appEngineHttpRequest: {
    httpMethod: 'POST',
    relativeUri: '/log_payload',
  },
};

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

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

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

package.json 파일을 확인합니다.

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

Ruby

require "google/cloud/tasks"

# Create an App Engine Task
#
# @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 App Engine Queue ID.
# @param [String] payload The request body of your task.
# @param [Integer] seconds The delay, in seconds, to process your task.
def create_task project_id, location_id, queue_id, payload: nil, seconds: nil
  # Instantiates a client.
  client = Google::Cloud::Tasks.new

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

  # Construct task.
  task = {
    app_engine_http_request: {
      http_method:  "POST",
      relative_uri: "/log_payload"
    }
  }

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

  # 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, task

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

다음 단계