JVM 言語

その言語が次の要件に遵守している限り、さまざまな JVM 言語(KotlinGroovyScala など)を使用して関数を記述できます。

  • 記述する関数は、機能インターフェース(HttpFunctionBackgroundFunctionRawBackgroundFunction)のいずれかを実装し、引数を持たないパブリックのコンストラクタを持つ public クラスの関数です。

  • ソースからデプロイする場合:

    • Maven からビルドできます。
    • ビルドファイルには、コンパイル済みのクラスを生成するためのすべてのプラグインが含まれています。
  • 事前にビルドされた JAR からデプロイする場合:

    • この JAR は任意のビルドツールを使用して作成できます。
    • 事前にビルドされた JAR は、すべての依存関係クラスを含む Fat JAR であるか、マニフェストに Class-Path エントリが含まれている必要があります。エントリには、それらの依存関係のクラスを含む jar の相対ロケーションの情報が入っていなければなりません。

HTTP 関数の例

HTTP 関数は、HTTP(S) リクエストを介して関数を呼び出す必要のある場合に使用します。次の例では、"Hello World!" というメッセージを出力します。

Kotlin

import com.google.cloud.functions.HttpFunction
import com.google.cloud.functions.HttpRequest
import com.google.cloud.functions.HttpResponse
import java.io.IOException
import java.util.logging.Logger

class KotlinHelloWorld : HttpFunction {
    // Simple function to return "Hello World"
    @Throws(IOException::class)
    override fun service(request: HttpRequest, response: HttpResponse) {
        response.writer.write("Hello World!")
    }
}

Groovy

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

class GroovyHelloWorld implements HttpFunction {
    @Override
    void service(HttpRequest request, HttpResponse response) {
        response.writer.write("Hello World!")
    }
}

Scala

class ScalaHelloWorld extends HttpFunction {
  override def service(httpRequest: HttpRequest, httpResponse: HttpResponse): Unit = {
    httpResponse.getWriter.write("Hello World!")
  }
}

HTTP の例での pom.xml ファイル

上記のサンプルの pom.xml ファイルは次のとおりです。

Kotlin

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example.cloud.functions</groupId>
  <artifactId>functions-kotlin-hello-world</artifactId>

  <properties>
    <maven.compiler.target>11</maven.compiler.target>
    <maven.compiler.source>11</maven.compiler.source>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <kotlin.version>1.4.20</kotlin.version>
  </properties>

  <dependencies>
    <!-- Required for Function primitives -->
    <dependency>
      <groupId>com.google.cloud.functions</groupId>
      <artifactId>functions-framework-api</artifactId>
      <version>1.0.2</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-stdlib-jdk8</artifactId>
      <version>${kotlin.version}</version>
    </dependency>
    <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-test</artifactId>
      <version>${kotlin.version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <!--
          Google Cloud Functions Framework Maven plugin

          This plugin allows you to run Cloud Functions Java code
          locally. Use the following terminal command to run a
          given function locally:

          mvn function:run -Drun.functionTarget=your.package.yourFunction
        -->
        <groupId>com.google.cloud.functions</groupId>
        <artifactId>function-maven-plugin</artifactId>
        <version>0.9.5</version>
        <configuration>
          <functionTarget>functions.KotlinHelloWorld</functionTarget>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.jetbrains.kotlin</groupId>
        <artifactId>kotlin-maven-plugin</artifactId>
        <version>${kotlin.version}</version>
        <executions>
          <execution>
            <id>compile</id>
            <phase>compile</phase>
            <goals>
              <goal>compile</goal>
            </goals>
            <configuration>
              <sourceDirs>
                <source>src/main/kotlin</source>
              </sourceDirs>
            </configuration>
          </execution>
          <execution>
            <id>test-compile</id>
            <phase>test-compile</phase>
            <goals>
              <goal>test-compile</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <jvmTarget>1.8</jvmTarget>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Groovy

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example.cloud.functions</groupId>
  <artifactId>functions-groovy-hello-world</artifactId>

  <properties>
    <maven.compiler.target>11</maven.compiler.target>
    <maven.compiler.source>11</maven.compiler.source>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <groovy.version>3.0.6</groovy.version>
  </properties>

  <dependencies>
    <!-- Required for Function primitives -->
    <dependency>
      <groupId>com.google.cloud.functions</groupId>
      <artifactId>functions-framework-api</artifactId>
      <version>1.0.2</version>
      <scope>provided</scope>
    </dependency>

    <!-- Required for groovy samples -->
    <dependency>
      <groupId>org.codehaus.groovy</groupId>
      <artifactId>groovy-all</artifactId>
      <version>${groovy.version}</version>
      <type>pom</type>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <!--
          Google Cloud Functions Framework Maven plugin

          This plugin allows you to run Cloud Functions Java code
          locally. Use the following terminal command to run a
          given function locally:

          mvn function:run -Drun.functionTarget=your.package.yourFunction
        -->
        <groupId>com.google.cloud.functions</groupId>
        <artifactId>function-maven-plugin</artifactId>
        <version>0.9.5</version>
        <configuration>
          <functionTarget>functions.GroovyHelloWorld</functionTarget>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.codehaus.gmavenplus</groupId>
        <artifactId>gmavenplus-plugin</artifactId>
        <version>1.11.0</version>
        <executions>
          <execution>
            <id>groovy-compile</id>
            <phase>process-resources</phase>
            <goals>
              <goal>addSources</goal>
              <goal>compile</goal>
            </goals>
          </execution>
        </executions>
        <dependencies>
          <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <!-- any version of Groovy \>= 1.5.0 should work here -->
            <version>${groovy.version}</version>
            <scope>runtime</scope>
            <type>pom</type>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>
</project>

Scala

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example.cloud.functions</groupId>
  <artifactId>functions-scala-hello-world</artifactId>

  <properties>
    <maven.compiler.target>11</maven.compiler.target>
    <maven.compiler.source>11</maven.compiler.source>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <!-- Required for scala samples -->
    <dependency>
      <groupId>org.scala-lang</groupId>
      <artifactId>scala-library</artifactId>
      <version>2.13.4</version>
    </dependency>

    <!-- Required for Function primitives -->
    <dependency>
      <groupId>com.google.cloud.functions</groupId>
      <artifactId>functions-framework-api</artifactId>
      <version>1.0.2</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <!--
          Google Cloud Functions Framework Maven plugin

          This plugin allows you to run Cloud Functions Java code
          locally. Use the following terminal command to run a
          given function locally:

          mvn function:run -Drun.functionTarget=your.package.yourFunction
        -->
        <groupId>com.google.cloud.functions</groupId>
        <artifactId>function-maven-plugin</artifactId>
        <version>0.9.5</version>
        <configuration>
          <functionTarget>functions.ScalaHelloWorld</functionTarget>
        </configuration>
      </plugin>
      <plugin>
        <groupId>net.alchim31.maven</groupId>
        <artifactId>scala-maven-plugin</artifactId>
        <version>4.4.0</version>
        <executions>
          <execution>
            <id>scala-compile</id>
            <phase>process-resources</phase>
            <goals>
              <goal>add-source</goal>
              <goal>compile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

HTTP 関数のデプロイ

Kotlin

gcloud functions deploy kotlin-helloworld --entry-point functions.KotlinHelloWorld --runtime java11 --trigger-http --allow-unauthenticated --memory 512MB

Groovy

gcloud functions deploy groovy-helloworld --entry-point functions.GroovyHelloWorld --runtime java11 --trigger-http --allow-unauthenticated --memory 512MB

Scala

gcloud functions deploy scala-helloworld --entry-point functions.ScalaHelloWorld --runtime java11 --trigger-http --allow-unauthenticated --memory 512MB

バックグラウンド関数の例

Google Cloud Pub/Sub トピックのメッセージ、Google Cloud Storage バケットの変更、Firebase イベントなどの非同期のイベントによって Cloud Functions の関数を間接的に呼び出す場合は、バックグラウンド関数を使用します。

Kotlin

import com.google.cloud.functions.BackgroundFunction
import com.google.cloud.functions.Context
import functions.eventpojos.PubSubMessage
import java.nio.charset.StandardCharsets
import java.util.Base64
import java.util.logging.Logger

class KotlinHelloPubSub : BackgroundFunction<PubSubMessage> {
    override fun accept(message: PubSubMessage, context: Context) {
        // name's default value is "world"
        var name = "world"
        if (message?.data != null) {
            name = String(
                    Base64.getDecoder().decode(message.data!!.toByteArray(StandardCharsets.UTF_8)),
                    StandardCharsets.UTF_8)
        }
        LOGGER.info(String.format("Hello %s!", name))
        return;
    }

    companion object {
        private val LOGGER = Logger.getLogger(KotlinHelloPubSub::class.java.name)
    }
}

バックグラウンド関数を開発する場合は、関数をトリガーするイベントのクラスを定義します。ただし、イベントクラスが特定のガイドラインに遵守していない場合、GSON マーシャリングはすぐには Kotlin で使用できないことがあります。

Kotlin のイベントクラスでは、プロパティが次のガイドラインに遵守する必要があります。

  • null に設定できる。
  • デフォルト値が割り当てられていない。
  • 委任プロパティではない。

もう 1 つの方法として、Java でイベントクラスを作成し、Kotlin 関数クラスから使用することもできます。

Groovy

import com.google.cloud.functions.BackgroundFunction
import com.google.cloud.functions.Context
import functions.eventpojos.PubSubMessage
import java.nio.charset.StandardCharsets
import java.util.logging.Logger

class GroovyHelloPubSub implements BackgroundFunction<PubSubMessage> {
    private static final Logger LOGGER = Logger.getLogger(GroovyHelloPubSub.class.name)

    @Override
    void accept(PubSubMessage message, Context context) {
        // name's default value is "world"
        String name = "world"

        if (message?.data) {
             name = new String(Base64.decoder.decode(message.data), StandardCharsets.UTF_8)
        }

        LOGGER.info("Hello ${name}!")
        return
    }
}

Scala

import java.nio.charset.StandardCharsets
import java.util.Base64
import java.util.logging.Logger

import com.google.cloud.functions.{BackgroundFunction, Context}
import functions.eventpojos.PubSubMessage

class ScalaHelloPubSub extends BackgroundFunction[PubSubMessage] {

  val LOGGER = Logger.getLogger(this.getClass.getName)

  override def accept(message: PubSubMessage, context: Context): Unit = {
    // name's default value is "world"
    var name = "world"
    if (message != null && message.getData != null) {
      name = new String(Base64.getDecoder.decode(
        message.getData.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8)
    }
    LOGGER.info(String.format("Hello %s!", name))
  }
}

バックグラウンド関数のデプロイ

Kotlin

gcloud functions deploy kotlin-hello-pubsub --entry-point functions.KotlinHelloPubSub --runtime java11 --trigger-topic my-topic --allow-unauthenticated --memory 512MB

Groovy

gcloud functions deploy groovy-hello-pubsub --entry-point functions.GroovyHelloPubSub --runtime java11 --trigger-topic my-topic --allow-unauthenticated --memory 512MB

Scala

gcloud functions deploy scala-hello-pubsub --entry-point functions.ScalaHelloPubSub --runtime java11 --trigger-topic my-topic --allow-unauthenticated --memory 512MB

バックグラウンドの例をテストする

次の手順に従って、バックグラウンドの例をテストできます。

  1. Pub/Sub トピックにメッセージを公開して、関数をトリガーします。

    gcloud pubsub topics publish my-topic --message Flurry
  2. ログを確認します。

    gcloud functions logs read --limit 10

Pub/Sub トピックに公開した名前を含むメッセージが次のように表示されます。

D      my-function  ...  Function execution started
I      my-function  ...  Hello Flurry!
D      my-function  ...  Function execution took 39 ms, finished with status: 'ok'