[Functions] クラウドイベントからFunctionsを自動的に呼び出し/Invoking Functions Automatically With Cloud Events

原文はこちら

ここDeveloper Blogでわたしはいくつかサーバレスファンクションを作成、そして実行するやり方を説明するポストをいくつか書いてきましたが、これまでのところそれらのポストでは、ファンクションをマニュアルで呼び出す、あるいはOCI Java SDKを使ったプログラムから呼び出すやりかただけにしか言及してきませんでした。今回のポストではファンクション呼び出しのもっとパワフルなやり方、すなわちクラウドテナンシー内での特定のアクションに対応して自動で呼び出しを行うやり方を説明したいと思います。このやり方では最近リリースされたCloud Eventsサービスを活用していきます。
このポストでわたしたちが見ていくことになるのは、あなたのテナンシーのObject Storageバケット内でオブジェクトが更新された際にひとつのOracle Functionをトリガーする、という例です。クラウドイベントを使って、画像イメージからメタデータを取得するファンクションを呼び出します。
このポストの内容に入る前に、以下に関連する以前のポストを紹介します。Oracle Functionsを初めて知ったという方は、これらのポストを読むことで入門的な知識、また、ファンクションを作成してマニュアルで起動する際に生じる疑問への答えが見つかるでしょう。

サーバレスアプリケーションの作成

まずはファンクションとして使うための新しいサーバレスアプリケーションを作成するとことから始めます。以前のわたしのポストでは、Fn CLIを使用してアプリケーションを作成していました。なので今回はクラウドダッシュボードを使ってみましょう。サイドバーからDeveloper Services -> Functionsと進んでください。
次に、'Create Application'をクリックして出てくるページの入力欄を埋めましょう。Fn CLIではサブネットのOCIDを直接指定する必要がありましたが、ここでは作成済のVCNがリストされるので適切なサブネットを選べるようになっていますね:
また、スクリーンショットでもう一点注目してほしいのは出力されたログをあとから見られるよう、PapertrailのログURLを指定していることです。こういうこともできるわけですね。
では、ローカルの端末に戻ってアプリケーションを作成しましょう:
fn init --runtime java cloud-events-demo-fn
 pom.xml ファイルにふたつの依存対象を追加します。ひとつは cloudevents-apiで、もうひとつはあとでメタデータを展開するときに使う metadata-extractor です。
<dependency>
    <groupId>io.cloudevents</groupId>
    <artifactId>cloudevents-api</artifactId>
    <version>0.2.1</version>
</dependency>
<dependency>
    <groupId>com.drewnoakes</groupId>
    <artifactId>metadata-extractor</artifactId>
    <version>2.12.0</version>
</dependency>
view rawpom.xml hosted with ❤ by GitHub
次にファンクション用のテストを書きましょう。先にご自身でObject Storageバケットにまずサンプル画像をアップロードしておく必要があります。その後、以下のJSONをテストに使ってください(テスト用の画像名、テナンシー名、バケット名は適宜置き換えてください):
{
"cloudEventsVersion": "0.1",
"eventID": "[UUID]",
"eventType": "com.oraclecloud.objectstorage.createobject",
"source": "objectstorage",
"eventTypeVersion": "1.0",
"eventTime": "2019-07-31T17:41:03Z",
"schemaURL": null,
"contentType": "application/json",
"extensions": {
"compartmentId": "ocid1.compartment.oc1...."
},
"data": {
"compartmentId": "ocid1.compartment.oc1....",
"compartmentName": "[compartment name]",
"resourceName": "[test image name.jpg]",
"resourceId": "",
"availabilityDomain": "all",
"freeFormTags": {
},
"definedTags": {
},
"additionalDetails": {
"eTag": "[UUID]",
"namespace": "[tenancy name]",
"archivalState": "Available",
"bucketName": "[bucket name]",
"bucketId": "ocid1.bucket.oc1.phx..."
}
}
}
view rawcloud-event.json hosted with ❤ by GitHub
テスト画像をアップロードして、JSONを修正したら、以下のようにテストができます:
package com.example.fn;
import com.fnproject.fn.testing.*;
import org.junit.*;
import static org.junit.Assert.*;
public class HelloFunctionTest {
    @Rule
    public final FnTestingRule testing = FnTestingRule.createDefault();
    @Test
    public void shouldReturnGreeting() {
        String event = "[your test image event JSON]";
        testing.givenEvent().withBody(event).enqueue();
        testing.thenRun(HelloFunction.class, "handleRequest");
        FnResult result = testing.getOnlyResult();
        assertTrue(result.isSuccess());
    }
}
テストはこの時点では失敗するはずです。それではテストが通るようにファンクションを実装していきましょう。Oracle Cloud EventsはCNCF Cloud Eventsに準拠しているので、インカミングのパラメータを CloudEvent として安全に型にすることができ、ファンクションがトリガーされるとFDKがパラメータを適切にシリアライズしたうえで扱ってくれます。CloudEventデータが取得できれば、画像(今回はパブリックな画像)を示すURLを構成でき、URLをストリームとして開いてメタデータエクストラクタにわたすことができます。
package com.example.fn;
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.metadata.Metadata;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.cloudevents.CloudEvent;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Map;
public class HelloFunction {
    public Metadata handleRequest(CloudEvent event) throws IOException, ImageProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        Map data = objectMapper.convertValue(event.getData().get(), Map.class);
        Map additionalDetails = objectMapper.convertValue(data.get("additionalDetails"), Map.class);
        String imageUrl = "https://objectstorage.us-phoenix-1.oraclecloud.com/n/" +
                additionalDetails.get("namespace") +
                "/b/" +
                additionalDetails.get("bucketName") +
                "/o/" +
                data.get("resourceName");
        InputStream imageStream = new URL(imageUrl).openStream();
        Metadata metadata = ImageMetadataReader.readMetadata(imageStream);
        System.out.println(objectMapper.writeValueAsString(metadata));
        //todo: do something with the metadata
        return metadata;
    }
}
view rawHelloFunction.java hosted with ❤ by GitHub
この時点でテストが通るようになっており、ファンクションをアプリケーションに以下のコマンドでデプロイできます:
fn deploy --app cloud-events-demo
以下のようにイベントJSONをわたすことでこれをマニュアルで実行することができます:
echo "[event JSON string]" | fn invoke cloud-events-demo cloud-events-demo-fn

ファンクションが想定通り動くことが確認できたでしょう。では、クラウドイベントルールを作成しましょう!

Cloud Eventの作成

新しいクラウドイベントルールを作成するには、サイドバーメニューからApplication Integration -> Events Serviceを選択してください:
'Create Rule'をクリックするとフォームが表示されるので、埋めていきます:
上記のスクリーンショットでの条件に注目してください。わたしは'Service Name'として'Object Storage'を選択して、また、'Event Type'として'Object Storage - Create Object'を選択しています。イベントをAttributeでフィルタすることもできますが、今回はわたしの特定のバケットへのオブジェクトのアップロードを引っ掛けたいだけです。イベントタイプやフィルター方法はいくつかのものから選ぶことができますので、詳細を知りたい方はサービスのドキュメントを参照してください。
残りの部分は以下のようにします:
ここでこのクラウドイベントが発動したときにとりたいアクションを指定しています。この例ではわたしたちは作成したサーバレスファンクションを呼びたいわけですが、Oracle Streamにパブリッシュしたり通知を送信したりもできますよ。'Create Rule'をクリックするとこのルールが即座に利用可能になります。

ルールのテスト

ルールをテストするには、単純にルールで指定したバケットにファイルをアップロードすればいいだけです。そのやり方のひとつにOCI CLIを使う方法があります:
oci os object put --bucket-name object-upload-demo-public --file /Users/trsharp/Pictures/test.jpg
数秒待ってからあなたのPapertrailログをチェックしてみると、System.outと書いたメタデータが出ているでしょう。以下はわたしがアップロードしたテスト画像のものをフォーマットしたものです:

まとめ

このポストでは画像のメタデータを展開するサーバレスファンクションを作成して、指定したObject Storageのバケットに画像がアップロードされると自動的に起動されるようにしました。クラウドイベントルールはOCIテナンシーの中での様々なアクション、例えばDatabaseやObject Storageに関するアクティビティーに結び付けられ、サーバレスファンクションや通知、Oracle Streamへのパブリッシュを自動的にトリガーすることが学べました。

0 件のコメント:

コメントを投稿