Memicu Cloud Functions menggunakan Cloud Tasks


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

Tujuan

  • Pahami kode di setiap komponen.
  • Membuat akun SendGrid.
  • Download kode sumbernya.
  • Men-deploy Cloud Function untuk menerima permintaan Cloud Tasks dan mengirim email melalui SendGrid API.
  • Membuat antrean Cloud Tasks.
  • Buat akun layanan untuk mengautentikasi permintaan Cloud Tasks Anda.
  • Deploy kode klien yang memungkinkan pengguna mengirim email.

Biaya

Cloud Tasks, Cloud Functions, dan App Engine memiliki paket gratis. Selama Anda menjalankan tutorial dalam paket gratis untuk produk yang ditentukan, tutorial tersebut tidak akan menimbulkan biaya tambahan. Untuk mengetahui informasi selengkapnya, lihat Harga.

Sebelum memulai

  1. Pilih atau buat project Google Cloud.

    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 catat lokasi tersebut. Perlu diperhatikan bahwa dua lokasi, yang disebut europe-west dan us-central dalam perintah App Engine, masing-masing dipanggil europe-west1 dan us-central1 dalam perintah Cloud Tasks.

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

    4. Jika 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 Get started, klik Next. Anda akan menanganinya nanti.

  3. Mengaktifkan Cloud Functions dan Cloud Tasks API.

    Mengaktifkan API

  4. Menginstal dan melakukan inisialisasi gcloud CLI.

Memahami kode

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

Membuat tugas

Halaman indeks ditayangkan menggunakan pengendali 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 sebenarnya membuat tugas dan mengirimkannya ke antrean Cloud Tasks. Kode ini membuat tugas dengan:

  • Menentukan jenis target sebagai HTTP Request.

  • Menentukan HTTP method yang akan digunakan dan URL target.

  • Menyetel header Content-Type ke application/json sehingga aplikasi downstream dapat mengurai payload terstruktur.

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

  • Memeriksa guna memastikan input pengguna untuk tanggal berada dalam rentang 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 menghasilkan Cloud Function yang merupakan 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, res) => {
  // Get the SendGrid API key from the environment variable.
  const key = process.env.SENDGRID_API_KEY;
  if (!key) {
    const error = new Error(
      'SENDGRID_API_KEY was not provided as environment variable.'
    );
    error.code = 401;
    throw error;
  }
  sendgrid.setApiKey(key);

  // Get the body from the Cloud Task request.
  const {to_email, to_name, from_name} = req.body;
  if (!to_email) {
    const error = new Error('Email address not provided.');
    error.code = 400;
    throw error;
  } else if (!to_name) {
    const error = new Error('Recipient name not provided.');
    error.code = 400;
    throw error;
  } else if (!from_name) {
    const error = new Error('Sender name not provided.');
    error.code = 400;
    throw error;
  }

  // Construct the email request.
  const msg = {
    to: to_email,
    from: 'postcard@example.com',
    subject: 'A Postcard Just for You!',
    html: postcardHTML(to_name, from_name),
  };

  try {
    await sendgrid.send(msg);
    // Send OK to Cloud Task queue to delete task.
    res.status(200).send('Postcard Sent!');
  } catch (error) {
    // Any status code other than 2xx or 503 will trigger the task to retry.
    res.status(error.code).send(error.message);
  }
};

Menyiapkan aplikasi

Menyiapkan SendGrid

  1. Membuat akun SendGrid.

  2. Membuat kunci API SendGrid:

    1. Login ke akun SendGrid Anda.

    2. Di navigasi sebelah kiri, buka Setelan dan klik Kunci API.

    3. Klik Create API Key lalu pilih akses terbatas. Di bawah header Kirim Email, pilih Akses Penuh.

    4. Salin Kunci API saat ditampilkan (Anda hanya akan melihatnya sekali, pastikan untuk menempelkannya di suatu tempat sehingga Anda dapat menggunakannya nanti).

Mendownload kode sumber

  1. Clone repositori aplikasi contoh ke komputer lokal Anda:

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git
    
  2. Ubah ke direktori yang berisi kode contoh:

    cd cloud-tasks/
    

Men-deploy Cloud Function

  1. Buka direktori function/:

    cd function/
    
  2. Deploy fungsi tersebut:

    gcloud functions deploy sendEmail --runtime nodejs14 --trigger-http \
      --no-allow-unauthenticated \
      --set-env-vars SENDGRID_API_KEY=SENDGRID_API_KEY \
    

    Ganti SENDGRID_API_KEY dengan kunci API Anda.

    Perintah ini menggunakan flag:

    • --trigger-http untuk menentukan jenis pemicu Cloud Functions.

    • --no-allow-unauthenticated untuk menentukan pemanggilan fungsi memerlukan autentikasi.

    • --set-env-var untuk menetapkan kredensial SendGrid Anda

  3. Tetapkan kontrol akses untuk fungsi agar hanya mengizinkan pengguna yang terautentikasi.

    1. Pilih fungsi sendEmail di UI Cloud Functions.

    2. Jika Anda tidak melihat info izin untuk sendEmail, klik TAMPILKAN Panel INFO di pojok kanan atas.

    3. Klik tombol Add principals di atas.

    4. Tetapkan New principals ke allAuthenticatedUsers.

    5. Tetapkan Role.

      • Fungsi generasi pertama (generasi ke-1): tetapkan peran ke Cloud Function Invoker
      • Fungsi generasi kedua (generasi ke-2): tetapkan peran ke Cloud Run Invoker
    6. Klik SAVE.

Membuat antrean Cloud Tasks

  1. Buat antrean menggunakan perintah gcloud berikut:

    gcloud tasks queues create my-queue --location=LOCATION
    

    Ganti LOCATION dengan lokasi pilihan Anda untuk antrean, misalnya, us-west2. Jika Anda tidak menentukan lokasinya, gcloud CLI akan memilih default-nya.

  2. Pastikan data berhasil dibuat:

    gcloud tasks queues describe my-queue --location=LOCATION
    

    Ganti LOCATION dengan lokasi antrean.

Membuat akun layanan

Permintaan Cloud Tasks harus memberikan kredensial di header Authorization agar Cloud Function dapat mengautentikasi permintaan. Akun layanan ini memungkinkan Cloud Tasks membuat dan menambahkan token OIDC untuk tujuan tersebut.

  1. Di Service accounts UI, klik +CREATE SERVICE ACCOUNT.

  2. Tambahkan nama akun layanan(nama tampilan yang ramah), lalu pilih buat.

  3. Tetapkan Role lalu klik Continue.

    • Fungsi generasi pertama (generasi ke-1): tetapkan peran ke Cloud Function Invoker
    • Fungsi generasi kedua (generasi ke-2): tetapkan peran ke Cloud Run Invoker
  4. Pilih Selesai.

Men-deploy endpoint dan pembuat tugas ke App Engine

  1. Buka direktori app/:

    cd ../app/
    
  2. Perbarui variabel di app.yaml dengan nilai Anda:

    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"

    Untuk menemukan lokasi antrean, gunakan perintah berikut:

    gcloud tasks queues describe my-queue --location=LOCATION
    

    Ganti LOCATION dengan lokasi antrean.

    Untuk menemukan URL fungsi Anda, gunakan perintah berikut:

    gcloud functions describe sendEmail
    
  3. Deploy aplikasi ke lingkungan standar App Engine, menggunakan perintah berikut:

    gcloud app deploy
    
  4. Buka aplikasi untuk mengirim kartu pos sebagai email:

    gcloud app browse
    

Pembersihan

Setelah menyelesaikan tutorial, Anda dapat membersihkan resource yang dibuat agar resource tersebut berhenti menggunakan kuota dan dikenai biaya. Bagian berikut menjelaskan cara menghapus atau menonaktifkan resource ini.

Menghapus Resource

Anda dapat membersihkan resource yang Anda buat di Google Cloud agar tidak menghabiskan kuota dan Anda tidak akan ditagih di masa mendatang. Bagian berikut menjelaskan cara menghapus atau menonaktifkan referensi ini.

Menghapus Cloud Function

  1. Buka halaman Cloud Functions di Konsol Google Cloud.

    Buka halaman Cloud Functions.

  2. Klik kotak centang di samping fungsi Anda.

  3. Klik tombol Delete di bagian atas halaman dan konfirmasi penghapusan Anda.

Menghapus antrean Cloud Tasks

  1. Buka halaman antrean Cloud Tasks di konsol.

    Buka halaman antrean Cloud Tasks

  2. Pilih nama antrean yang ingin dihapus, lalu klik Hapus antrean.

  3. Konfirmasi tindakan.

Menghapus project

Cara termudah untuk menghilangkan penagihan adalah dengan menghapus project yang Anda buat untuk tutorial.

Untuk menghapus project:

  1. Di konsol Google Cloud, buka halaman Manage resource.

    Buka Manage resource

  2. Pada daftar project, pilih project yang ingin Anda hapus, lalu klik Delete.
  3. Pada dialog, ketik project ID, lalu klik Shut down untuk menghapus project.

Langkah selanjutnya