Cloud Tasks를 사용하여 Cloud Run 함수 트리거

이 튜토리얼에서는 App Engine 애플리케이션 내에서 Cloud Tasks를 사용하여 Cloud Run 함수를 트리거하고 예약된 이메일을 보내는 방법을 다룹니다.

목표

  • 각 구성 요소의 코드 이해하기
  • SendGrid 계정 만들기
  • 소스 코드 다운로드하기
  • Cloud Run 함수를 배포하여 Cloud Tasks 요청을 수신하고 SendGrid API를 통해 이메일 보내기
  • Cloud Tasks 큐 만들기
  • Cloud Tasks 요청을 인증하기 위한 서비스 계정 만들기
  • 사용자가 이메일을 보낼 수 있는 클라이언트 코드 배포하기

비용

Cloud Tasks, Cloud Run 함수, App Engine에는 무료 등급이 제공되므로 지정된 제품의 무료 등급에서 튜토리얼을 실행하는 한 추가 비용은 발생하지 않습니다. 자세한 내용은 가격 책정을 참조하세요.

시작하기 전에

  1. 프로젝트를 선택하거나 만듭니다. Google Cloud

    App Engine 페이지로 이동

  2. 프로젝트에서 App Engine 애플리케이션을 초기화하세요.

    1. App Engine 시작하기 페이지에서 애플리케이션 만들기를 클릭합니다.

    2. 애플리케이션의 리전을 선택합니다. 이 위치는 Cloud Tasks 요청의 LOCATION_ID 매개변수로 사용되므로 기록해두두세요. 두 위치는 App Engine 명령어에서는 europe-west 및 us-central로, Cloud Tasks 명령어에서는 europe-west1 및 us-central1로 각각 호출됩니다.

    3. 언어는 Node.js를 선택하고 환경은 표준을 선택합니다.

    4. 결제 사용 설정 팝업이 나타나면 결제 계정을 선택합니다. 현재 결제 계정이 없는 경우 결제 계정 만들기를 클릭하고 마법사의 안내에 따릅니다.

    5. 시작하기 페이지에서 다음을 클릭합니다. 이 부분은 나중에 처리합니다.

  3. Cloud Run 함수 및 Cloud Tasks API를 사용 설정합니다.

    API 사용 설정

  4. gcloud CLI를 설치하고 초기화합니다.

코드 이해하기

이 섹션에서는 앱 코드와 코드의 작동 방식을 살펴봅니다.

태스크 만들기

색인 페이지는 app.yaml의 핸들러를 사용하여 제공됩니다. 태스크 생성에 필요한 변수는 환경 변수로 전달됩니다.

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

이 코드는 엔드포인트 /send-email을 생성합니다. 이 엔드포인트는 색인 페이지에서 양식 제출을 처리하고 해당 데이터를 태스크 생성 코드에 전달합니다.

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! 💌');
});

이 코드는 실제로 태스크를 만들어 Cloud Tasks 큐로 보냅니다. 코드는 다음과 같이 태스크를 빌드합니다.

  • 대상 유형HTTP Request로 지정

  • 사용할 HTTP method와 대상의 URL 지정

  • 다운스트림 애플리케이션이 구조화된 페이로드를 파싱할 수 있도록 Content-Type 헤더를 application/json으로 설정

  • Cloud Tasks가 인증이 필요한 요청 대상에 사용자 인증 정보를 제공할 수 있도록 서비스 계정 이메일 추가. 서비스 계정은 별도로 생성됩니다.

  • 날짜에 대한 사용자 입력이 최대 30일 이내인지 확인하고 이를 필드 scheduleTime으로 요청에 추가

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)