Memicu fungsi Cloud Run menggunakan Cloud Tasks

Tutorial ini menunjukkan cara menggunakan Cloud Tasks dalam aplikasi App Engine untuk memicu fungsi Cloud Run dan mengirim email terjadwal.

Tujuan

  • Pahami kode di setiap komponen.
  • Buat akun SendGrid.
  • Download kode sumber.
  • Deploy fungsi Cloud Run untuk menerima permintaan Cloud Tasks dan mengirim email melalui SendGrid API.
  • Buat antrean Cloud Tasks.
  • Buat akun layanan untuk mengautentikasi permintaan Cloud Tasks Anda.
  • Deploy kode klien yang memungkinkan pengguna mengirim email.

Biaya

Cloud Tasks, fungsi Cloud Run, dan App Engine memiliki paket gratis, jadi selama Anda menjalankan tutorial dalam paket gratis produk tertentu, tidak akan ada biaya tambahan. Untuk mengetahui informasi selengkapnya, lihat Harga.

Sebelum memulai

  1. Pilih atau buat Google Cloud project.

    Buka halaman App Engine

  2. Lakukan inisialisasi aplikasi App Engine di project Anda:

    1. Di halaman Welcome to App Engine, klik Create Application.

    2. Pilih region untuk aplikasi Anda. Lokasi ini akan berfungsi sebagai parameter LOCATION_ID untuk permintaan Cloud Tasks Anda, jadi catatlah. Perhatikan bahwa dua lokasi, yang disebut europe-west dan us-central dalam perintah App Engine, masing-masing disebut europe-west1 dan us-central1 dalam perintah Cloud Tasks.

    3. Pilih Node.js untuk bahasa dan Standard untuk lingkungan.

    4. Jika jendela pop-up Aktifkan penagihan muncul, pilih akun penagihan Anda. Jika saat ini Anda tidak memiliki akun penagihan, klik Buat akun penagihan dan ikuti wizard.

    5. Di halaman Mulai, klik Berikutnya. Anda akan menanganinya nanti.

  3. Aktifkan Cloud Run Functions dan Cloud Tasks API.

    Aktifkan API

  4. Menginstal dan melakukan inisialisasi gcloud CLI.

Memahami kode

Bagian ini akan memandu Anda mempelajari kode aplikasi dan menjelaskan cara kerjanya.

Membuat tugas

Halaman indeks ditayangkan menggunakan handler di app.yaml. Variabel yang diperlukan untuk pembuatan tugas diteruskan sebagai variabel lingkungan.

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

Kode ini membuat endpoint /send-email. Endpoint ini menangani pengiriman formulir dari halaman indeks dan meneruskan data tersebut ke kode pembuatan tugas.

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

Kode ini benar-benar membuat tugas dan mengirimkannya ke antrean Cloud Tasks. Kode ini membangun tugas dengan:

  • Menentukan jenis target sebagai HTTP Request.

  • Menentukan HTTP method yang akan digunakan dan URL target.

  • Menetapkan header Content-Type ke application/json sehingga aplikasi hilir dapat mem-parsing payload terstruktur.

  • Menambahkan email akun layanan agar Cloud Tasks dapat memberikan kredensial ke target permintaan, yang memerlukan autentikasi. Akun layanan dibuat secara terpisah.

  • Memeriksa untuk memastikan input pengguna untuk tanggal berada dalam batas maksimum 30 hari dan menambahkannya ke permintaan sebagai kolom 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) / 1000;
    // Restrict schedule time to the 30 day maximum.
    if (date_diff_in_seconds > MAX_SCHEDULE_LIMIT) {
      console.error('Schedule time is over 30 day maximum.');
    }
    // Construct future date in Unix time.
    const date_in_seconds =
      Math.min(date_diff_in_seconds, MAX_SCHEDULE_LIMIT) + Date.now() / 1000;
    // Add schedule time to request in Unix time using Timestamp structure.
    // https://googleapis.dev/nodejs/tasks/latest/google.protobuf.html#.Timestamp
    task.scheduleTime = {
      seconds: date_in_seconds,
    };
  }

  try {
    // Send create task request.
    const [response] = await client.createTask({parent, task});
    console.log(`Created task ${response.name}`);
    return response.name;
  } catch (error) {
    // Construct error for Stackdriver Error Reporting
    console.error(Error(error.message));
  }
};

module.exports = createHttpTaskWithToken;

Membuat email

Kode ini membuat fungsi Cloud Run yang menjadi target untuk permintaan Cloud Tasks. Fungsi ini menggunakan isi permintaan untuk membuat email dan mengirimkannya melalui SendGrid API.

const sendgrid = require('@sendgrid/mail');

/**
 * Responds to an HTTP request from Cloud Tasks and sends an email using data
 * from the request body.
 *
 * @param {object} req Cloud Function request context.
 * @param {object} req.body The request payload.
 * @param {string} req.body.to_email Email address of the recipient.
 * @param {string} req.body.to_name Name of the recipient.
 * @param {string} req.body.from_name Name of the sender.
 * @param {object} res Cloud Function response context.
 */
exports.sendEmail = async (req