LoginSignup
3
5

More than 3 years have passed since last update.

CloudFunctionsで一定時間経過後に処理を実行する方法

Posted at

はじめに

CloudFunctionsで何らかの処理を実行して、その何分後かに別の処理を呼び出したいことがあります。
だけどsetTimeoutを使いたくない。事前にジョブを登録しておくわけにもいかない。

そんな時に以下の方法で実装してみました。

  • cloudSchedulerに対して、実行させたい日時(例:○分後)にジョブを登録。

  • 実行時刻になると処理が呼び出される。

  • 処理が終わったら不要になったジョブを削除。

参考:CloudSchedulerリファレンス

サンプルコード

index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const { google } = require('googleapis');
const cloudScheduler = google.cloudscheduler('v1beta1');
const moment = require('moment');

process.env.GOOGLE_APPLICATION_CREDENTIALS = 'path/to/serviceAccountKey.json';

async function authorize() {
  const auth = new google.auth.GoogleAuth({
    scopes: ['https://www.googleapis.com/auth/cloud-platform'],
  });
  return await auth.getClient();
}

const projectId = 'my-project-id';
const locationId = 'us-central1';
const topicName = 'my-topic-name';
const jobName = 'my-job-name';

// 10分後処理実行を登録する処理
exports.setTriggerIn10minutes = functions.https.onRequest(
  async (req, res) => {
    // 現在時刻の10分後を取得し、cronフォーマットを生成
    const cronStr = moment().add(10, 'minutes').format('m h D M *');
    // GCPのOAuth認証
    const authClient = await authorize();
    // ジョブ追加リクエストを作成
    const request = {
      parent: `projects/${projectId}/locations/${locationId}`,
      resource: {
        name: `projects/${projectId}/locations/${locationId}/jobs/${jobName}`,
        schedule: cronStr,
        pubsubTarget: {
          topicName: `projects/${projectId}/topics/${topicName}`,
          data: Buffer.from(`${topicName} ${cronStr}`).toString('base64'),
        },
      },
      auth: authClient,
    };
    // APIリクエスト
    try {
      const response = (await cloudScheduler.projects.locations.jobs.create(request)).data;
      console.log(JSON.stringify(response, null, 2));
    } catch (err) {
      console.error(err);
    }
    res.status(200).send('OK');
  }
);

// 10分後に呼び出される処理
exports.beCalledAfter10minutes = functions.pubsub.topic(topicName).onPublish(
  async (event, context) => {
    const pubsubMessage = event.data;
    console.log(Buffer.from(pubsubMessage, 'base64').toString());

    // TODO: 実際にやることを記述

    // GCPのOAuth認証
    const authClient = await authorize();
    // ジョブ削除リクエストを作成
    const request = {
      name: `projects/${projectId}/locations/${locationId}/jobs/${jobName}`,
      auth: authClient,
    };
    // APIリクエスト
    try {
      await cloudScheduler.projects.locations.jobs.delete(request);
    } catch (err) {
      console.error(err);
    }
  }
);

実行確認

最初の処理

ブラウザから以下のURLにアクセスし、Cloud Functionsを実行します。
https://location-id-my-project-id.cloudfunctions.net/setTriggerIn10minutes

Cloud Functionsのログを確認し、setTriggerIn10minutesが正常に実行されたことを確認します。
Cloud Schedulerのジョブ一覧を確認し、トピック:my-topic-nameのジョブが10分後の実行予定で追加されたことを確認します。

10分後に呼び出される処理

Cloud Functionsのログを確認し、beCalledAfter10minutesが正常に実行されたことを確認します。
Cloud Schedulerのジョブ一覧を確認し、トピック:my-topic-nameのジョブが削除されたことを確認します。

注意事項

  • FirebaseのSparkプラン(無料)では使えませんでした。Blazeプラン(従量制)にする必要あり。

  • Cloud Schedulerの管理者権限をIAMで割り当てる必要あり。

  • 実行時刻は秒単位での指定はできません。

といった制約があるので使える場面は少ないかもしれませんが、もしもの時に役立てばと思います。

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5