Cloud Run functions を作成する

このページでは、Functions Framework を使用して HTTP とイベント ドリブンの Cloud Run functions の関数を記述する方法について説明します。

Functions Framework の概要

関数のソースコードを記述する際は、Cloud Run functions の関数を記述するためのオープンソース ライブラリである Functions Framework を使用する必要があります。Functions Framework を使用すると、Cloud Run やローカル開発マシン、Knative ベースの環境など、さまざまな環境で実行される軽量の関数を記述できます。

Functions Framework では、次のことができます。

  • リクエストに応じて Cloud Run functions の関数を呼び出します。
  • イベントデータを一般的な方法で記述するための業界標準仕様である CloudEvents 仕様に適合したイベントを自動的にアンマーシャルします。
  • テスト用のローカル開発用サーバーを起動します。

Functions Framework は、モジュラー サービスを構築するためのインターフェースを提供します。ソースコードで Functions Framework を使用するには、以下のものを指定します。

関数のエントリ ポイント

ソースコードで関数のエントリ ポイントを定義する必要があります。これは、Cloud Run が関数を呼び出したときに実行されるコードです。このエントリ ポイントは、関数のデプロイ時に指定します。

エントリ ポイントの定義方法は、使用する言語ランタイムによって異なります。関数をエントリ ポイントとして使用する言語もあれば、クラスを使用するものもあります。

署名タイプ

Functions Framework で関数のソースコードを作成する場合は、次のいずれかの署名タイプを指定する必要があります。

  • HTTP 関数: HTTP ハンドラ関数を登録します。関数で URL エンドポイントを使用し、Webhook などの HTTP リクエストに応答する必要がある場合は、HTTP 関数を使用します。
  • イベント ドリブン関数(CloudEvents 関数とも呼ばれます): CloudEvents ハンドラ関数を登録します。Pub/Sub トピックのメッセージや Cloud Storage バケットの変更など、 Google Cloud プロジェクト内のイベントに応答して関数が直接トリガーされる場合は、イベント ドリブン関数を使用します。

ソース ディレクトリの構造

Functions Framework は、多くのプログラミング言語でサポートされています。選択した言語ランタイムと記述する関数のタイプによって、コードを構造化して関数を実装する方法が異なります。

Cloud Run で関数の定義を見つけられるように、言語ランタイムごとにソースコードの構造について要件があります。

Node.js

Node.js 関数の基本的なディレクトリ構造は次のとおりです。

.
├── index.js
└── package.json

デフォルトでは、Cloud Run は関数ディレクトリのルートにある index.js というファイルからソースコードを読み込みます。別のメイン ソースファイルを指定するには、package.json ファイルの main フィールドを使用します。

package.json ファイルには、依存関係として Functions Framework for Node.js も含める必要があります。

{
  "main": "index.js",
  "dependencies": {
    "@google-cloud/functions-framework": "^3.0.0"
  },
  "type": "module"
}

メインファイル内のコードで関数エントリ ポイントを定義する必要があります。他のコードと Node.js モジュールをインポートできます。メインファイルでは、個別にデプロイ可能な複数の関数エントリ ポイントを定義できます。

詳細については、Node.js ランタイムの概要Functions Framework for Node.js をご覧ください。

Python

Python 関数の基本的なディレクトリ構造は次のとおりです。

.
├── main.py
└── requirements.txt

Cloud Run は、関数ディレクトリのルートにある main.py という名前のファイルからソースコードを読み込みます。メインファイルの名前は main.py にする必要があります。

requirements.txt ファイルには、依存関係として Functions Framework for Python が含まれている必要があります。

functions-framework==3.*

main.py ファイルのコードで関数エントリ ポイントを定義する必要があります。他のコードと外部依存関係は通常どおりインポートできます。また、main.py ファイルを使用して、個別にデプロイできる複数の関数エントリ ポイントを定義することもできます。

詳細については、Python ランタイムの概要Functions Framework for Python をご覧ください。

Go

Go 関数の基本的なディレクトリ構造は次のとおりです。

.
├── myfunction.go
└── go.mod

関数は、Go パッケージ内のプロジェクトのルートに置く必要があります。パッケージとそのソースファイルには任意の名前を付けることができます。ただし、関数を package main に含めることはできません。ローカルテストなどで main パッケージが必要な場合は、サブディレクトリにパッケージを作成できます。

.
├── myfunction.go
├── go.mod
└── cmd/
  └── main.go

go.mod ファイルには、依存関係として Functions Framework for Go が含まれている必要があります。

module example.com/my-module

require (
  github.com/GoogleCloudPlatform/functions-framework-go v1.5.2
)

ルート パッケージのコードは関数エントリ ポイントを定義する必要があります。サブパッケージと依存関係から通常どおり他のコードをインポートできます。また、パッケージで、個別にデプロイできる複数の関数エントリ ポイントを定義することもできます。

詳細については、Go ランタイムの概要Functions Framework for Go をご覧ください。

Java

Java 関数の基本的なディレクトリ構造は次のとおりです。

.
├── pom.xml
└── src/
  └── main/
      └── java/
          └── MyFunction.java

Java のソースファイルは src/main/java/ ディレクトリに配置する必要があり、任意の名前を付けることができます。ソースファイルでパッケージが宣言されている場合は、src/main/java の下にパッケージの名前を含むディレクトリを追加します。

.
├── pom.xml
└── src/
  └── main/
      └── java/
          └── mypackage/
              └── MyFunction.java

関連するテストを src/test/java/ サブディレクトリに配置することをおすすめします。

pom.xml ファイルには、依存関係として Functions Framework for Java が含まれている必要があります。

...
    <dependency>
      <groupId>com.google.cloud.functions</groupId>
      <artifactId>functions-framework-api</artifactId>
      <version>1.0.4</version>
    </dependency>
...

ソースファイルのコードは関数のエントリ ポイントを定義します。他のコードおよび外部依存関係は通常どおりインポートできます。また、ソースファイルで、個別にデプロイできる複数の関数エントリ ポイントを定義することもできます。

詳細については、Java ランタイムの概要Functions Framework for Java をご覧ください。

.NET

.NET 関数の基本的なディレクトリ構造は次のとおりです。

.
├── MyFunction.cs
└── MyProject.csproj

プロジェクトは、他の .NET ソースコードと同じように構造化できます。ソースファイルには任意の名前を付けることができます。

プロジェクト ファイルには、依存関係として Functions Framework for .NET が含まれている必要があります。

...
    <PackageReference Include="Google.Cloud.Functions.Hosting" Version="1.0.0" />
...

ソースファイルのコードは関数のエントリ ポイントを定義します。他のコードおよび外部依存関係は通常どおりインポートできます。また、ソースファイルで、個別にデプロイできる複数の関数エントリ ポイントを定義することもできます。

詳細については、.NET ランタイムの概要Functions Framework for .NET をご覧ください。

Ruby

Ruby 関数の基本的なディレクトリ構造は次のとおりです。

.
├── app.rb
├── Gemfile
└── Gemfile.lock

Cloud Run は、関数ディレクトリのルートにある app.rb という名前のファイルからソースコードを読み込みます。メインファイルの名前は app.rb にする必要があります。

Gemfile ファイルには、依存関係として Functions Framework for Ruby が含まれている必要があります。

source "https://rubygems.org"
gem "functions_framework", "~> 1.0"

app.rb ファイルのコードで関数エントリ ポイントを定義する必要があります。他のコードと外部依存関係は通常どおりインポートできます。また、app.rb ファイルを使用して、個別にデプロイできる複数の関数エントリ ポイントを定義することもできます。

詳細については、Ruby ランタイムの概要Functions Framework for Ruby をご覧ください。

PHP

PHP 関数の基本的なディレクトリ構造は次のとおりです。

.
├── index.php
└── composer.json

Cloud Run は、関数ディレクトリのルートにある index.php という名前のファイルからソースコードを読み込みます。メインファイルの名前は index.php にする必要があります。

composer.json ファイルには、依存関係として Functions Framework for PHP が含まれている必要があります。

{
  "require": {
    "google/cloud-functions-framework": "^1.1"
  }
}

index.php ファイルのコードで関数エントリ ポイントを定義する必要があります。他のコードと外部依存関係は通常どおりインポートできます。また、index.php ファイルを使用して、個別にデプロイできる複数の関数エントリ ポイントを定義することもできます。

詳細については、PHP ランタイムの概要Functions Framework for PHP をご覧ください。

複数の関数を 1 つのプロジェクトにグループ化する場合、すべての関数が同じ依存関係のセットを共有する結果になる可能性があります。ただし、一部の関数は依存関係の全部は必要としない場合があります。

可能であれば、大規模な関数のコードベースを分割し、上記の例のように、独自のソースファイルとプロジェクト構成ファイルで各関数を最上位のディレクトリに配置することをおすすめします。このアプローチにより、特定の関数に必要な依存関係の数が最小限に抑えられ、関数が必要とするメモリ量が削減されます。

HTTP 関数を作成する

HTTP(S) リクエストを介して関数を呼び出す場合は、HTTP 関数を作成します。HTTP セマンティクスを許可するには、Function Framework を使用して、HTTP 固有の引数を受け入れるように HTTP 関数シグネチャを指定します。

以下に、各ランタイムの基本的な HTTP 関数のソースファイルを示します。完全な動作例については、Google Cloud CLI を使用して Cloud Run functions の関数をデプロイするをご覧ください。ソースコードの場所について詳しくは、ソース ディレクトリ構造をご覧ください。

Node.js

ES モジュール

  import { http } from '@google-cloud/functions-framework';
  http('myHttpFunction', (req, res) => {
    // Your code here

    // Send an HTTP response
    res.send('OK');
  });

package.json ファイルに "type": "module" を含む次の依存関係を追加します。

  {
    "dependencies": {
      "@google-cloud/functions-framework": "^3.0.0"
    },
    "type": "module"
  }

CommonJS モジュール

  const functions = require('@google-cloud/functions-framework');

  // Register an HTTP function with the Functions Framework
  functions.http('myHttpFunction', (req, res) => {
    // Your code here

    // Send an HTTP response
    res.send('OK');
  });

package.json ファイルに次の依存関係を追加します。

  {
    "dependencies": {
      "@google-cloud/functions-framework": "^3.0.0"
    }
  }

Node.js で Functions Framework for Node.js を使用して、HTTP ハンドラ関数を登録します。HTTP ハンドラ関数は、リクエストレスポンスの引数を受け入れて HTTP レスポンスを送信する Express ミドルウェア関数である必要があります。

Cloud Run では、body-parser を使用して、リクエストの Content-Type ヘッダーに基づいてリクエスト本文を自動的に解析するため、HTTP ハンドラ内の req.body または req.rawBody オブジェクトにアクセスできます。

関数のエントリ ポイントは、ハンドラを Functions Framework に登録したときに使用した名前です。この例では、エントリ ポイントは myHttpFunction です。

Python

import functions_framework

# Register an HTTP function with the Functions Framework
@functions_framework.http
def my_http_function(request):
  # Your code here

  # Return an HTTP response
  return 'OK'

Python で、Functions Framework for Python を使用して HTTP ハンドラ関数を登録します。HTTP ハンドラ関数は、Flask リクエストのオブジェクトを引数として受け取り、Flask が HTTP レスポンス オブジェクトに変換可能な値を返す必要があります。

関数のエントリ ポイントは、ハンドラを Functions Framework に登録したときに使用した名前です。この例では、エントリ ポイントは my_http_function です。

Go

package myhttpfunction

import (
    "fmt"
    "net/http"

    "github.com/GoogleCloudPlatform/functions-framework-go/functions"
)

func init() {
    // Register an HTTP function with the Functions Framework
    functions.HTTP("MyHTTPFunction", myHTTPFunction)
}

// Function myHTTPFunction is an HTTP handler
func myHTTPFunction(w http.ResponseWriter, r *http.Request) {
    // Your code here

    // Send an HTTP response
    fmt.Fprintln(w, "OK")
}

Go で、Functions Framework for Go を使用して init() 関数で HTTP ハンドラ関数を登録します。HTTP ハンドラ関数は、標準の http.HandlerFunc インターフェースを使用して HTTP レスポンスを送信する必要があります。

関数のエントリ ポイントは、ハンドラを Functions Framework に登録したときに使用した名前です。この例では、エントリ ポイントは MyHTTPFunction です。

HTTP ハンドラ関数は、標準の http.HandlerFunc インターフェースを実装する必要があります。関数がリクエストへの応答を作成するために使用する http.ResponseWriter インターフェースと、インバウンド HTTP リクエストの詳細情報を含む http.Request 構造体へのポインタを受け入れます。

Java

package myhttpfunction;

import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;

// Define a class that implements the HttpFunction interface
public class MyHttpFunction implements HttpFunction {
  // Implement the service() method to handle HTTP requests
  @Override
  public void service(HttpRequest request, HttpResponse response) throws Exception {
    // Your code here

    // Send an HTTP response
    response.getWriter().write("OK");
  }
}

Java では、Functions Framework Java API を使用して、HttpFunction インターフェースを持つ HTTP ハンドラクラスを実装します。service() メソッドは HTTP レスポンスを送信する必要があります。

関数のエントリ ポイントは、HTTP ハンドラクラスの完全修飾名(パッケージ名を含む)です。この例では、エントリ ポイントは myhttpfunction.MyHttpFunction です。

service メソッドは、インバウンド HTTP リクエストを記述する HttpRequest オブジェクトと、関数によってレスポンス メッセージが設定される HttpResponse オブジェクトを受け取ります。

.NET

using Google.Cloud.Functions.Framework;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;

namespace MyProject
{
    // Define a class that implements the IHttpFunction interface
    public class MyHttpFunction : IHttpFunction
    {
        // Implement the HandleAsync() method to handle HTTP requests
        public async Task HandleAsync(HttpContext context)
        {
            // Your code here

            // Send an HTTP response
            await context.Response.WriteAsync("OK");
        }
    }
}

.NET ランタイムで、Functions Framework for .NET を使用して、IHttpFunction インターフェースを持つ HTTP ハンドラクラスを実装します。HandleAsync() メソッドは、標準の ASP.NET HttpContext オブジェクトを引数として受け取り、HTTP レスポンスを送信する必要があります。

関数のエントリ ポイントは、HTTP ハンドラクラスの完全修飾名(名前空間を含む)です。この例では、エントリ ポイントは MyProject.MyHttpFunction です。

Ruby

require "functions_framework"

# Register an HTTP function with the Functions Framework
FunctionsFramework.http "my_http_function" do |request|
  # Your code here

  # Return an HTTP response
  "OK"
end

Ruby では、Functions Framework for Ruby を使用して HTTP ハンドラ関数を登録します。HTTP ハンドラ関数は、Rack リクエスト オブジェクトを引数として受け取り、HTTP レスポンスとして使用可能な値を返す必要があります。

関数のエントリ ポイントは、ハンドラを Functions Framework に登録したときに使用した名前です。この例では、エントリ ポイントは my_http_function です。

PHP

<?php

use Google\CloudFunctions\FunctionsFramework;
use Psr\Http\Message\ServerRequestInterface;

// Register an HTTP function with the Functions Framework
FunctionsFramework::http('myHttpFunction', 'myHttpHandler');

// Define your HTTP handler
function myHttpHandler(ServerRequestInterface $request): string
{
    // Your code here

    // Return an HTTP response
    return 'OK';
}

PHP で、Functions Framework for PHP を使用して HTTP ハンドラ関数を登録します。HTTP ハンドラ関数は、PSR-7 ServerRequestInterface インターフェースを実装する引数を受け取り、文字列または PSR-7 ResponseInterface インターフェースを実装しているオブジェクトとして HTTP レスポンスを返す必要があります。

関数のエントリ ポイントは、ハンドラを Functions Framework に登録したときに使用した名前です。この例では、エントリ ポイントは myHttpFunction です。

HTTP リクエストとレスポンス

Functions Framework に HTTP ハンドラ関数を登録すると、HTTP ハンドラはリクエスト メソッドを検査し、メソッドに応じてさまざまなアクションを実行できます。

Cloud Run 関数に HTTP リクエストを送信するようにイベント プロバイダを構成すると、関数は HTTP レスポンスを送信します。関数によってバックグラウンド タスク(スレッド、Future、JavaScript Promise オブジェクト、コールバック、システム プロセスなど)が作成される場合は、HTTP レスポンスが送信される前に、これらのタスクを終了します。あるいは、他の方法で問題を解決する必要があります。HTTP レスポンスが送信される前に終了しなかったタスクは完了しません。未定義の動作が行われる可能性があります。

CORS を処理する

クロスオリジン リソース シェアリング(CORS)は、あるドメインで実行されているアプリケーションが別のドメインのリソースにアクセスできるようにする方法です。たとえば、関数にアクセスするために、ドメインから Cloud Run functions のドメインへのリクエストを許可する必要があるとします。

関数に対するクロスオリジン リクエストを許可するには、HTTP レスポンスに適切な Access-Control-Allow-Origin ヘッダーを設定します。プリフライトされたクロスオリジン リクエストの場合、204 レスポンス コードと追加のヘッダーを使用して、プリフライトの OPTIONS リクエストに応答する必要があります。

Node.js

const functions = require('@google-cloud/functions-framework');

/**
 * HTTP function that supports CORS requests.
 *
 * @param {Object} req Cloud Function request context.
 * @param {Object} res Cloud Function response context.
 */
functions.http('corsEnabledFunction', (req, res) => {
  // Set CORS headers for preflight requests
  // Allows GETs from any origin with the Content-Type header
  // and caches preflight response for 3600s

  res.set('Access-Control-Allow-Origin', '*');

  if (req.method === 'OPTIONS') {
    // Send response to OPTIONS requests
    res.set('Access-Control-Allow-Methods', 'GET');
    res.set('Access-Control-Allow-Headers', 'Content-Type');
    res.set('Access-Control-Max-Age', '3600');
    res.status(204).send('');
  } else {
    res.send('Hello World!');
  }
});

Python

import functions_framework

@functions_framework.http
def cors_enabled_function(request):
    # For more information about CORS and CORS preflight requests, see:
    # https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request

    # Set CORS headers for the preflight request
    if request.method == "OPTIONS":
        # Allows GET requests from any origin with the Content-Type
        # header and caches preflight response for an 3600s
        headers = {
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Methods": "GET",
            "Access-Control-Allow-Headers": "Content-Type",
            "Access-Control-Max-Age": "3600",
        }

        return ("", 204, headers)

    # Set CORS headers for the main request
    headers = {"Access-Control-Allow-Origin": "*"}

    return ("Hello World!", 200, headers)

Go


// Package http provides a set of HTTP Cloud Functions samples.
package http

import (
	"fmt"
	"net/http"

	"github.com/GoogleCloudPlatform/functions-framework-go/functions"
)

// CORSEnabledFunction is an example of setting CORS headers.
// For more information about CORS and CORS preflight requests, see
// https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request.
func CORSEnabledFunction(w http.ResponseWriter, r *http.Request) {
	// Set CORS headers for the preflight request
	if r.Method == http.MethodOptions {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "POST")
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
		w.Header().Set("Access-Control-Max-Age", "3600")
		w.WriteHeader(http.StatusNoContent)
		return
	}
	// Set CORS headers for the main request.
	w.Header().Set("Access-Control-Allow-Origin", "*")
	fmt.Fprint(w, "Hello, World!")
}

func init() {
	functions.HTTP("CORSEnabledFunction", CORSEnabledFunction)
}

Java


import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import java.io.BufferedWriter;
import java.io.IOException;
import java.net.HttpURLConnection;

public class CorsEnabled implements HttpFunction {
  // corsEnabled is an example of setting CORS headers.
  // For more information about CORS and CORS preflight requests, see
  // https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request.
  @Override
  public void service(HttpRequest request, HttpResponse response)
      throws IOException {
    // Set CORS headers
    //   Allows GETs from any origin with the Content-Type
    //   header and caches preflight response for 3600s
    response.appendHeader("Access-Control-Allow-Origin", "*");

    if ("OPTIONS".equals(request.getMethod())) {
      response.appendHeader("Access-Control-Allow-Methods", "GET");
      response.appendHeader("Access-Control-Allow-Headers", "Content-Type");
      response.appendHeader("Access-Control-Max-Age", "3600");
      response.setStatusCode(HttpURLConnection.HTTP_NO_CONTENT);
      return;
    }

    // Handle the main request.
    BufferedWriter writer = response.getWriter();
    writer.write("CORS headers set successfully!");
  }
}

.NET

using Google.Cloud.Functions.Framework;
using Microsoft.AspNetCore.Http;
using System.Net;
using System.Threading.Tasks;

namespace Cors;

// For more information about CORS and CORS preflight requests, see
// https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request.
public class Function : IHttpFunction
{
    public async Task HandleAsync(HttpContext context)
    {
        HttpRequest request = context.Request;
        HttpResponse response = context.Response;

        // Set CORS headers
        //   Allows GETs from any origin with the Content-Type
        //   header and caches preflight response for 3600s

        response.Headers.Append("Access-Control-Allow-Origin", "*");
        if (HttpMethods.IsOptions(request.Method))
        {
            response.Headers.Append("Access-Control-Allow-Methods", "GET");
            response.Headers.Append("Access-Control-Allow-Headers", "Content-Type");
            response.Headers.Append("Access-Control-Max-Age", "3600");
            response.StatusCode = (int) HttpStatusCode.NoContent;
            return;
        }

        await response.WriteAsync("CORS headers set successfully!", context.RequestAborted);
    }
}

Ruby

FunctionsFramework.http "cors_enabled_function" do |request|
  # For more information about CORS and CORS preflight requests, see
  # https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
  # for more information.

  # Set CORS headers for the preflight request
  if request.options?
    # Allows GET requests from any origin with the Content-Type
    # header and caches preflight response for an 3600s
    headers = {
      "Access-Control-Allow-Origin"  => "*",
      "Access-Control-Allow-Methods" => "GET",
      "Access-Control-Allow-Headers" => "Content-Type",
      "Access-Control-Max-Age"       => "3600"
    }
    [204, headers, []]
  else
    # Set CORS headers for the main request
    headers = {
      "Access-Control-Allow-Origin" => "*"
    }

    [200, headers, ["Hello World!"]]
  end
end

PHP


use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use GuzzleHttp\Psr7\Response;

function corsEnabledFunction(ServerRequestInterface $request): ResponseInterface
{
    // Set CORS headers for preflight requests
    // Allows GETs from any origin with the Content-Type header
    // and caches preflight response for 3600s
    $headers = ['Access-Control-Allow-Origin' => '*'];

    if ($request->getMethod() === 'OPTIONS') {
        // Send response to OPTIONS requests
        $headers = array_merge($headers, [
            'Access-Control-Allow-Methods' => 'GET',
            'Access-Control-Allow-Headers' => 'Content-Type',
            'Access-Control-Max-Age' => '3600'
        ]);
        return new Response(204, $headers, '');
    } else {
        return new Response(200, $headers, 'Hello World!');
    }
}

CORS が正しく設定されていないと、次のようなエラーが表示されることがあります。

XMLHttpRequest cannot load https://YOUR_FUNCTION_URL.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'https://YOUR_DOMAIN' is therefore not allowed access.

CORS の制限

プリフライトされたクロスオリジン リクエストの場合、プリフライトの OPTIONS リクエストは Authorization ヘッダーなしで送信されるため、認証が必要なすべての HTTP 関数でリクエストが拒否されます。プリフライト リクエストが失敗するため、メイン リクエストも失敗します。この制限を回避するには、次のいずれかのオプションを使用します。

イベント ドリブン関数を作成する

Pub/Sub トピックのメッセージや Cloud Storage バケットの変更など、 Google Cloud プロジェクト内のイベントに応答して関数を直接トリガーする場合は、イベント ドリブン関数を作成します。

イベント ドリブン関数は、イベントデータを一般的な方法で記述するための業界標準仕様である CloudEvents をベースにしています。CloudEvents 仕様の詳細については、CloudEvents GitHub リポジトリをご覧ください。CloudEvents プロジェクトには、コード内の CloudEvents オブジェクトを操作するための一連の CloudEvents SDK も用意されています。

次の例は、各ランタイムのイベント ドリブン関数のソースファイルを示しています。ソースコードの場所については、ソース ディレクトリ構造をご覧ください。

Node.js

ES モジュール

  import { cloudEvent } from "@google-cloud/functions-framework";
  cloudEvent('myCloudEventFunction', cloudEvent => {
    // Your code here
    // Access the CloudEvent data payload using cloudEvent.data
  });

package.json ファイルに "type": "module" を含む次の依存関係を追加します。

  {
    "dependencies": {
      "@google-cloud/functions-framework": "^3.0.0"
    },
    "type": "module"
  }

CommonJS モジュール

const functions = require('@google-cloud/functions-framework');

// Register a CloudEvent function with the Functions Framework
functions.cloudEvent('myCloudEventFunction', cloudEvent => {
  // Your code here
  // Access the CloudEvent data payload using cloudEvent.data
});

package.json ファイルに次の依存関係を追加します。

  {
    "dependencies": {
      "@google-cloud/functions-framework": "^3.0.0"
    }
  }

Node.js では、CloudEvent ハンドラ関数を Functions Framework for Node.js で登録します。ハンドラ関数は、CloudEvent オブジェクトを引数として受け入れる必要があります。

関数のエントリ ポイントは、ハンドラを Functions Framework に登録したときに使用した名前です。この例では、エントリ ポイントは myCloudEventFunction です。

Python

import functions_framework

# Register a CloudEvent function with the Functions Framework
@functions_framework.cloud_event
def my_cloudevent_function(cloud_event):
  # Your code here
  # Access the CloudEvent data payload via cloud_event.data

Python では、CloudEvent ハンドラ関数を Functions Framework for Python に登録します。ハンドラ関数は、CloudEvent オブジェクトを引数として受け入れる必要があります。

関数のエントリ ポイントは、Functions Framework に登録されたハンドラ関数の名前です。この例では、エントリ ポイントは my_cloudevent_function です。

Go

package mycloudeventfunction

import (
    "context"

    "github.com/GoogleCloudPlatform/functions-framework-go/functions"
    "github.com/cloudevents/sdk-go/v2/event"
)

func init() {
    // Register a CloudEvent function with the Functions Framework
    functions.CloudEvent("MyCloudEventFunction", myCloudEventFunction)
}

// Function myCloudEventFunction accepts and handles a CloudEvent object
func myCloudEventFunction(ctx context.Context, e event.Event) error {
    // Your code here
    // Access the CloudEvent data payload using e.Data() or e.DataAs(...)

    // Returning an error causes its message to be logged.
    // Example:
    err := myInternalFunction() // may return an error
    if err != nil {
        // Append error message to log
        return err
    }

    // Return nil if no error occurred
    return nil
}

Go では、CloudEvent ハンドラ関数を Functions Framework for Go に登録します。ハンドラ関数は、CloudEvents event.Event オブジェクトを引数として受け入れる必要があります。

関数のエントリ ポイントは、ハンドラを Functions Framework に登録したときに使用した名前です。この例では、エントリ ポイントは MyCloudEventFunction です。

Java

package mycloudeventfunction;

import com.google.cloud.functions.CloudEventsFunction;
import io.cloudevents.CloudEvent;

// Define a class that implements the CloudEventsFunction interface
public class MyCloudEventFunction implements CloudEventsFunction {
  // Implement the accept() method to handle CloudEvents
  @Override
  public void accept(CloudEvent event) {
    // Your code here
    // Access the CloudEvent data payload using event.getData()
    // To get the data payload as a JSON string, use:
    // new String(event.getData().toBytes())
  }
}

Java では、Functions Framework Java API を使用して、CloudEventsFunction インターフェースを持つ CloudEvent ハンドラクラスを実装します。accept() メソッドは、CloudEvent オブジェクトを引数として受け取り、イベントに対する処理を行う必要があります。

関数のエントリ ポイントは、パッケージ名を含む CloudEvent ハンドラクラスの完全修飾名です。この例では、エントリ ポイントは mycloudeventfunction.MyCloudEventFunction です。

.NET

using CloudNative.CloudEvents;
using Google.Cloud.Functions.Framework;
using System.Threading;
using System.Threading.Tasks;

namespace MyProject
{
  // Define a class that implements the ICloudEventFunction<T> interface
  public class MyCloudEventFunction : ICloudEventFunction<CloudEventDataType>
  {
      // Implement the HandleAsync() method to handle CloudEvents
      public Task HandleAsync(CloudEvent cloudEvent, CloudEventDataType data, CancellationToken cancellationToken)
      {
          // Your code here
          // The data argument represents the CloudEvent data payload

          // Signal function completion
          return Task.CompletedTask;
      }
  }
}

.NET ランタイムでは、Functions Framework for .NET を使用して、ICloudEventFunction<T> インターフェースを持つ CloudEvent ハンドラクラスを実装します。HandleAsync() メソッドは、引数として CloudEvent オブジェクトとそれに関連する CloudEvent データ ペイロードを受け取ります。

CloudEvent データ ペイロード引数の型(例のコードでは CloudEventDataType)は、関数が処理するイベントの種類に対応している必要があります。Google CloudEvents .NET ライブラリには、Google でサポートされているさまざまなイベントのデータ型が用意されています。

関数のエントリ ポイントは、CloudEvent ハンドラクラスの完全修飾名(名前空間を含む)です。この例では、エントリ ポイントは MyProject.MyCloudEventFunction です。

Ruby

require "functions_framework"

# Register a CloudEvent function with the Functions Framework
FunctionsFramework.cloud_event "my_cloudevent_function" do |cloud_event|
  # Your code here
  # Access the CloudEvent data payload via cloud_event.data
end

Ruby では、CloudEvent ハンドラ関数を Functions Framework for Ruby に登録します。ハンドラ関数は、CloudEvents Event オブジェクトを引数として受け入れる必要があります。

関数のエントリ ポイントは、ハンドラを Functions Framework に登録したときに使用した名前です。この例では、エントリ ポイントは my_cloudevent_function です。

PHP

<?php

use CloudEvents\V1\CloudEventInterface;
use Google\CloudFunctions\FunctionsFramework;

// Register a CloudEvent function with the Functions Framework
FunctionsFramework::cloudEvent('myCloudEventFunction', 'myCloudEventHandler');

// Define your CloudEvent handler
function myCloudEventHandler(CloudEventInterface $event): void
{
    // Your code here
    // Access the CloudEvent data payload using $event->getData()
}

PHP では、CloudEvent ハンドラ関数を Functions Framework for PHP に登録します。ハンドラ関数は、CloudEventInterface インターフェースに適合する引数を受け入れる必要があります。

関数のエントリ ポイントは、ハンドラを Functions Framework に登録したときに使用した名前です。この例では、エントリ ポイントは myCloudEventFunction です。

イベント ドリブン関数の場合、イベントデータは CloudEvents 形式で関数に渡されます。CloudEvent データ ペイロードは、関数をトリガーするイベントタイプに対応します。サポートされているトリガー、イベントタイプ、関連するイベントデータの形式については、関数のトリガーをご覧ください。

Google イベント リポジトリには、Google が発行する CloudEvents を使用するためのリソースが含まれています。

関数の終了

関数から制御が戻ると、Cloud Run はイベント ドリブン関数の実行が終了したと判断します。関数によってバックグラウンド タスク(スレッド、Future、JavaScript Promise オブジェクト、コールバック、システム プロセスなど)が作成される場合は、関数から制御が戻る前に、これらのタスクを終了します。あるいは、他の方法で問題を解決する必要があります。関数が返される前に終了しなかったタスクは完了しません。未定義の動作が行われる可能性があります。

自動再試行

失敗した呼び出しを自動的に再試行するように、イベント ドリブン関数を構成できます。詳細については、イベント ドリブン関数の再試行をご覧ください。

次のステップ