X

A blog about Oracle Technology Network Japan

サーバーレスOracle Functionsを呼び出すための完全ガイド

Guest Author

※本記事は、Todd Sharpによる"The Complete Guide To Invoking Serverless Oracle Functions"を翻訳したものです。

July 23, 2020


Oracle Functionsについては、数多くの情報をこのブログにて共有し、ファンクションの呼出しに関する例もさまざま紹介してきました。しかし、Oracle Cloudでサーバーレスのファンクションを呼び出すさまざまな方法も含め、すべてを包括した総合的なガイドを作成したことはありませんでした。そこで今回は、サーバーレスのファンクションを呼び出すための(このブログを掲載する時点で可能な)すべての方法を紹介していきたいと思います。
以下の目次には、このブログの各セクションに移動できる便利なリンクを付けていますので、どうぞご活用ください。

 

ファンクション・メタデータの取得

ファンクションを呼び出す前に、まずはそのファンクションに関する情報を取得しておく必要があります。ここでは、ファンクション名とファンクションをデプロイするアプリケーション名についてはすでに把握しているものの、その他の情報についてはまだ把握していないと仮定します。今回は以下の情報を使用します。なおこのブログでは、実際のデータの代わりに使用するプレースホルダを[ ]で示しています。

  • ファンクション名 [function-name]
  • ファンクション・アプリケーション名 [application-name]
  • ファンクションOCID [function-ocid]
  • ファンクション呼出しエンドポイント [invoke-endpoint] (コレクション・メソッドによっては、これを [invoke-endpoint-base-url] から取得する必要があるかもしれません)

では、これらの情報を取得する方法を見ていきましょう。

 

Fn CLIを使用

個人的には、Fn CLIを使用して以下のコマンドを実行するやり方が、もっとも迅速かつ簡単にこれらの情報を取得できる方法だと思っています。

  $ fn inspect function [application-name] [function-name]
view raw fn-invoke.sh hosted with ❤ by GitHub

例:

  $ fn inspect function hello-world-app hello-world-fn
view raw inspect.sh hosted with ❤ by GitHub

結果は、ファンクション・メタデータを含むJSONで表示されます。


上の例では、(1)に[invoke-endpoint]があり、(2)に[function-ocid]があります。

 

コンソール・ダッシュボードを使用

OCIコンソール・ダッシュボードにて、必要なファンクション・アプリケーションを選択し、ファンクション名をクリックしてファンクション情報を確認します。この情報画面には、[function-ocid] が表示され(1)、[invoke-endpoint]も確認できますが、前の例のfn inspectとは異なり、ここに表示されるのは[invoke-endpoint-base-url]のみとなります。

 

注:このブログの初回掲載時点では、[invoke-endpoint-base-url]がわかっており、これが常に以下の形式にある場合のみ、[invoke-endpoint]を取得できます

[invoke-endpoint-base-url]/20181201/functions/[function-ocid]/actions/invoke

 

OCI CLIを使用

最後に、OCI CLIを使用して情報を取得する方法を紹介します。

  $ oci fn function get --function-id [function-ocid]
view raw oci-get.sh hosted with ❤ by GitHub

 

[function-ocid](1)と[invoke-endpoint-base-url](2)が返されます。[invoke-endpoint]はこの情報から取得する必要があります。

 

ファンクションの呼出し

必要なデータを取得できたら、呼び出しの作業に移ります。

こちらもご覧ください! Oracle Cloud でのサーバーレス・ファンクションの呼び出し方法を確認されているということは、きっとサーバーレスのOracle Functionsのロギングについても関心をお持ちかと思います。その場合は、どうぞこちらをご覧ください。

 

テストまたはデバック目的の呼出し

まずはテストまたはデバッグ目的の呼出しについて紹介します。つまりシンプルなリクエストにてコマンドラインからシンプルな結果を取得し、ファンクションをテストする場合の方法です。

 

Fn CLIを使用

このメソッドはすでにご存じかもしれませんが、このブログは完全ガイドですので、これについても簡単に押さえておきます。

  $ fn invoke [application-name] [function-name]
view raw fn-invoke.sh hosted with ❤ by GitHub

データをファンクションの呼出しにパスする必要がある場合は、echoを使用し、データをfn invokeコールにパイプします。

  $ echo "{'name': 'todd'}" | fn invoke hello-world-app hello-world-fn
view raw fn-invoke.sh hosted with ❤ by GitHub

 

OCI CLIを使用

OCI CLI にてファンクションを呼び出すことも可能です。ファイルの引数では、ファンクションの結果が入るファイルへのパスが指定されます("-"はSTDOUTへリダイレクト)。また本文の引数にて、入力内容をファンクションへ渡すこともできます。なお、OCI CLIを使用する場合、前のFn CLIの例で使用した[application-name]と[function-name]ではなく、[function-ocid]が必要です。

 

  oci fn function invoke --file "-" --body '{"name": "todd"}' --function-id [function-ocid]
view raw oci-invoke.sh hosted with ❤ by GitHub

 

OCI-CURLを使用

他にも、oci-curlを使用してコマンドラインにてファンクションを呼び出すこともできます。

ご承知おきください: 私はこのメソッドはお勧めしません。Fn CLIの方が(またはOCI CLIでも)呼出しは遥かに簡単なため、この方法を用いる必要がないからです。しかし、このメソッドが機能するものであることは事実であり、またCLIツールをインストールできないがテストのためにファンクションを呼び出す必要があることもあるかもしれないため、お勧めしないながらも私はこの方法を掲載しました。したがってこの方法を採用するか否かは、皆さんの裁量にお任せします。

ディスクには、POSTリクエストにて呼出しエンドポイントに送信した本文を含むテキストファイルが必要です。入力内容を渡す必要がない場合も、ディスクには、本文の入っていない空のファイルが必要です。私がoci-curlを書いたわけではないので、私には質問しないでくださいね?

  $ echo '{"name": "todd"}' > /tmp/body.json
view raw write-body.sh hosted with ❤ by GitHub

では、ファンクションを呼び出します。具体的には、以下のとおりです。

  oci-curl
  "[invoke-endpoint-base-url]"
  POST
  /tmp/body.json
  "/20181201/functions/[function-ocid]/actions/invoke"
view raw oci-curl.sh hosted with ❤ by GitHub

 

トリガーやイベントに応じた自動的な呼出し

Oracle Functions は Oracle Cloud Infrastructure の一連のサービスと深く統合されています。そのためさまざまな方法にて、イベントや、特定のトリガーに呼応して、サーバーレス・ファンクションを呼び出すことができます。

 

Oracle Notification Serviceを使用

通知トピックへのサブスクリプションを作成し、これによりファンクションを呼び出すことができます。

ヒント! 通知は非常に便利です。詳しくは、通知サービスの開発者向け完全ガイドをご覧ください。

新しいトピックを作成するか、既存のトピックを入力して、「Create Subscription」をクリックします。プロトコルとして「Functions」を選択し、通知を受け取ったときに呼び出したいファンクションを検索して選択します。

詳しくは、通知とファンクションの統合に関するガイドをご覧ください。

 

クラウドのイベントを使用

クラウドのイベント・トリガーに呼応してサーバーレス・ファンクションを呼び出すこともできます。Oracle Cloudにてクラウド・イベントを生成するサービスが数多くあることや、メトリクスやアラームに基づいてクラウドのイベントをトリガーできることを考えると、この統合は非常に便利です。Oracle SDKと組み合わせると、クラウドのアクションやリソースを詳細にコントロールすることができます。

クラウドのイベントからファンクションを呼び出すには、次のようにルールを作成します。

 

詳しくは、クラウドのイベントによるファンクションの呼出しに関するブログをご覧ください。

 

Oracle Integration Cloud(OIC)を使用

私はOracle Integration Cloudを使用したことがないため、このメソッドについ詳しく説明することはできませんが、Oracle Integration Cloudからサーバーレス・ファンクションを呼び出すことは可能です。詳しくは、OICのドキュメントをご覧ください。

 

HTTPリクエストおよびSDKを使った手動による呼出し

最後に、アプリケーション・インフラストラクチャの一部としてサーバーレス・ファンクションを実装する際に開発者がもっともよく用いると思われるメソッドの1つである、HTTPまたはSDKを使った手動によるファンクションの呼出しについて説明します。

 

HTTPリクエスト(API Gateway経由)を使用

OCI API Gatewayサービスを使用すれば、サーバーレス・ファンクションをHTTPにて示すことができます(認証、CORS、およびレート制限の設定は任意)。まずは、ゲートウェイを作成するか、既存のゲートウェイを選択し、「Create Deployment」をクリックします。

 

「From Scratch」を選択し、名前とパスのプリフィックスを入力します。

 

必要に応じて、認証、CORS、レート制限、ロギングを設定し、「Next」をクリックします。

 

「Routes」タブにて、(1)パス(ワイルドカードも可)、(2)HTTPメソッド、(3)Oracle Functions、(4)アプリケーション、(5)ファンクション名を入力します。

 

次の画面で入力内容を確認し、「Create」をクリックします。変更内容がデプロイされたら、デプロイメントの情報にてそのデプロイメントの呼出しエンドポイントを見つけます。これは、ファンクション呼出しエンドポイントとは異なります。

 

この呼出しエンドポイントをベースURLとして使用し、上で指定したルートパスを追加すると、ゲートウェイ経由でファンクションを呼び出すことができます。

 

Java SDKを使用

OCI Java SDKには、サーバーレスのOCIファンクションを呼び出すメソッドが2つあります。1つは従来のブロッキングクライアントを使う方法で、もう1つはコールバックを必要とする非同期クライアントによるノンブロッキングの方法です。
OCI Java SDKでファンクションを呼び出すには、まず以下の依存関係があることを確認する必要があります。ここではGradleを使用していますが、もし別のビルドシステムを使用している場合は、それに合わせて調整してください。

  compile('javax.activation:javax.activation-api:1.2.0')
  compile('com.oracle.oci.sdk:oci-java-sdk-common:1.19.3')
  compile('com.oracle.oci.sdk:oci-java-sdk-functions:1.19.3')
view raw build.gradle hosted with ❤ by GitHub

現時点では、Java 11以降でのファンクションの呼出しには問題があるため、以下のようにスクリプトにシステム・プロパティを設定してTLS 1.2を使用するようにすることで、その問題を回避します。

  /* when using Java 11+, force TLS 1.2 */
  System.setProperty("jdk.tls.client.protocols", "TLSv1.2");

次に、[function-ocid]と[invoke-endpoint-base-url] を設定し、認証プロバイダのインスタンスを作成します。

  String functionId = " [function-ocid]";
  String invokeEndpoint = "[invoke-endpoint-base-url]";
  ConfigFileAuthenticationDetailsProvider provider = new ConfigFileAuthenticationDetailsProvider("DEFAULT");

次に、呼出しリクエストと一緒に送信するペイロードを作成します。ここでは、JSONにシリアライズするMapを作成します。またこれは呼出しリクエストとともに送信する本文としても使用します。

  /* generate the payload */
  Map<String, String> payloadMap = new HashMap<>();
  payloadMap.put("name", "Sync Client");
  ObjectMapper mapper = new ObjectMapper();
  String payload = mapper.writeValueAsString(payloadMap);

次に、FunctionsInvokeClientのインスタンスを作成し、呼出しリクエストを構成し、そのリクエストをクライアントのinvokeFunctionメソッドにパスします。これにより応答を解析したり、クライアントをクローズしたり、STDOUTへの応答を印刷したりすることが可能になります。

  /* use sync client */
  FunctionsInvokeClient functionsInvokeClient = FunctionsInvokeClient.builder()
          .endpoint(invokeEndpoint)
          .build(provider);
  InvokeFunctionRequest request = InvokeFunctionRequest.builder()
          .functionId(functionId)
          .invokeFunctionBody(
                  StreamUtils.createByteArrayInputStream(payload.getBytes())
          )
          .build();
  InvokeFunctionResponse invokeFunctionResponse = functionsInvokeClient.invokeFunction(request);
  String syncResponse = IOUtils.toString(invokeFunctionResponse.getInputStream());
  functionsInvokeClient.close();
  System.out.println(syncResponse);

コンパイルし実行すると、以下が返されます。
{"message":"Hello Sync Client"}
このアプローチを部分的に変更すれば、非同期クライアントを使用してノンブロッキングのアプローチにすることができます。まずは以下のようにペイロードを変更します。

  /* use async client */
  payloadMap.replace("name", "Async Client");
  String asyncPayload = mapper.writeValueAsString(payloadMap);
view raw InvokeAsync.java hosted with ❤ by GitHub

次に、非同期クライアントと呼出しリクエストを構成します。

  FunctionsInvokeAsyncClient functionsInvokeAsyncClient = FunctionsInvokeAsyncClient.builder()       
  .endpoint(invokeEndpoint)       
  .build(provider);
  InvokeFunctionRequest asyncRequest = InvokeFunctionRequest.builder()       
  .functionId(functionId)       
  .invokeFunctionBody(StreamUtils.createByteArrayInputStream(asyncPayload.getBytes()))       
  .build();
view raw InvokeAsync.java hosted with ❤ by GitHub

前のアプローチと少し異なる点があります。今回のアプローチでは、invokeFunctionコールにパスするためにAsyncHandlerが必要になります。これはこの呼出しの結果に対して作業する際に使用できます。

  AsyncHandler<InvokeFunctionRequest, InvokeFunctionResponse> handler = new AsyncHandler<>() {
  @Override
  public void onSuccess(InvokeFunctionRequest invokeFunctionRequest, InvokeFunctionResponse invokeFunctionResponse) {
  try {
  System.out.println(IOUtils.toString(invokeFunctionResponse.getInputStream()));
  } catch (IOException e) {
  e.printStackTrace();
  }
  }
   
  @Override
  public void onError(InvokeFunctionRequest invokeFunctionRequest, Throwable error) {
  error.printStackTrace();
  }
  };
view raw InvokeAsync.java hosted with ❤ by GitHub

最後に、リクエストとハンドラを非同期クライアントのinvokeFunctionメソッドに渡して、そのクライアントをクローズします。

  functionsInvokeAsyncClient.invokeFunction(asyncRequest, handler);
  functionsInvokeAsyncClient.close();
view raw InvokeAsync.java hosted with ❤ by GitHub

非同期メソッドを実行すると、以下が生成されます。

{"message":"Hello Async Client"}

 

TypeScript/JavaScript SDKを使用

OCI TypeScript/JavaScript SDKでも、サーバーレスのOCIのファンクションを呼び出すことができます。この場合、まずはSDKをノードプロジェクトにインストールします。

npm install oci-sdk

次に、必要なモジュールを取得し、authProviderを構成します。

  import fn = require("oci-functions");
  import common = require("oci-common");
  import helper = require("oci-common/lib/helper");
  const configurationFilePath = "~/.oci/config";
  const configProfile = "DEFAULT";
  const authProvider: common.ConfigFileAuthenticationDetailsProvider = 
        new common.ConfigFileAuthenticationDetailsProvider(
          configurationFilePath,
          configProfile
        );
view raw invoke-fn.ts hosted with ❤ by GitHub

[function-ocid]と[invoke-endpoint-base-url]を設定します。

  const functionId: string = "[function-ocid]";
  const invokeEndpoint: string = "[invoke-endpoint-base-url]";
view raw invoke-fn.ts hosted with ❤ by GitHub

クライアントを構成し、エンドポイントを設定します。

  const fnClient: fn.FunctionsInvokeClient = new fn.FunctionsInvokeClient({
    authenticationDetailsProvider: authProvider
  });
  fnClient.endpoint = invokeEndpoint;
view raw invoke-fn.ts hosted with ❤ by GitHub

リクエストを構成し、それをクライアントにパスし、結果を記録します。

  (async () => {
    const request: fn.requests.InvokeFunctionRequest = {
      functionId: functionId,
      invokeFunctionBody: JSON.stringify({
        name: "Todd"
      })
    };
    const response: fn.responses.InvokeFunctionResponse = await fnClient.invokeFunction(request);
    console.log(
        JSON.parse(
          await helper.getStringFromResponseBody(response.value)
        )
    )
  })()
view raw invoke-fn.ts hosted with ❤ by GitHub

TypeScriptをコンパイルし、呼び出します。

 

その他のSDKおよびAPIを使用

.NET、Python、Ruby、Go用のOCI SDKでもサーバーレスのファンクションを呼び出すことができます。詳しくは、それぞれのSDKのドキュメントを参照してください。 

またOCI REST APIでもサーバーレスのファンクションを直接呼び出すことができます。しかしこれにはHTTPリクエストへの手動による署名が必要となるため、難しい作業になるかもしれません。しかしここまで紹介したメソッドでは対応していない言語やプロトコロルを使用している場合は、この方法をお試しください。

ボーナス情報! Ashishが執筆したこちらのブログで紹介されている便利なメソッドを使って、PostmanでOCI REST APIを呼び出すことも可能です。このことを教えてくれたMatt Curtisに感謝します!

写真提供:Goh Rhy YanUnsplash)

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.