ほりひログ

所属組織の製品 (Azure とか) に関連する内容が多めだけど、個人の見解であって、所属組織を代表する公式情報ではないです。

Azure Functions Node.js の新しいプログラミング モデル

ここの issue で議論されてた新しいプログラミング モデル、情報がまとまって試せるものが出てきたのでローカル PC 環境で動かしてみた。

github.com

注意 : 2022 年 9 月現在、まだ "internal testing" phase (パブリック プレビューですらない) で議論中なので、変更の可能性は大いにあり。

変更ポイント ~ function.json の廃止

上述のリンク先でも Say goodbye 👋 to "function.json" files! って言ってる。一番影響でかそう。

function.json が廃止されると、function.json 内で設定していた

  1. エントリー ポイント
  2. トリガー / バインディング

を他で定義することになるので、簡単にその説明を。

1. エントリー ポイント

今のプログラミング モデルでは function.jsonscriptFile フィールドで定義していた (関数の) エントリー ポイントは、(モジュール全体のエントリー ポイントとして) package.jsonmain フィールドに移動、ロードしたい js ファイルのパスを指定することに。

package.json

{
    "name": "azure-functions-prototype",
    "version": "1.0.0",
    "description": "",
      :
    "main": "/PATH/TO/ENTRYPOINT.js",
      :
}

ちなみに、この main フィールドのパスの解析、globby を使って独自に行っているので、ワイルド カード (** , *) 指定での複数ファイルの読み込みが可能。

2. トリガー / バインディング

現状 function.jsonbindings フィールドで定義していたトリガー / バインディング設定は、新しいモデルでは上述のエントリー ポイントとして読み込まれたファイル内で、@azure\functions からインポートできる app にトリガーに対応するメソッド (get, timer, http, storageBlob etc) で登録していく。

以下、サンプルコード。

import { app, HttpRequest, InvocationContext} from "@azure/functions";

app.get('helloWorld1', async (context: InvocationContext, request: HttpRequest) => {
    context.log(`Http function processed request for url "${request.url}"`);

    const name = request.query.get('name') || await request.text() || 'world';

    return { body: `Hello, ${name}!` };
});

app.timer('timerTrigger1', {
    schedule: '0 */5 * * * *',
    handler: (context: InvocationContext, myTimer: Timer) => {
        const timeStamp = new Date().toISOString();
        context.log('The current time is: ', timeStamp);
    }
});

バインディングもコードで追加する。
以下、HTTP トリガーで実行して、その時に Blob コンテナーから特定のデータを入力バインディングで取得して、その内容を出力バインディングでキューに保存する、というサンプル。

import { app, HttpRequest, HttpResponse, input, InvocationContext, output } from "@azure/functions";

const queueOutput = output.storageQueue({
  queueName: 'testqueue',
  connection: 'storage_APPSETTING'
});
const blobInput = input.storageBlob({
  connection: 'storage_APPSETTING',
  path: 'testcontainer/testblob',
})
async function helloWorldWithExtraOutputs(context: InvocationContext, request: HttpRequest): Promise<HttpResponse> {
  context.log(`Http function processed request for url "${request.url}"`);

  const name = request.query.get('name') || await request.text() || 'world';

  if (process.env.storage_APPSETTING) {
    const message = context.extraInputs.get(blobInput);
    context.extraOutputs.set(queueOutput, message);
  }

  return { body: `Hello, ${name}!` };
}

const extraOutputs = [];
if (process.env.storage_APPSETTING) {
  extraOutputs.push(queueOutput);
}

const extraInputs = [];
if (process.env.storage_APPSETTING) {
  extraInputs.push(blobInput);
}

app.http('helloWorldWithExtraInputsOutputs', {
  authLevel: "anonymous",
  methods: ['GET', 'POST'],
  extraOutputs,
  extraInputs,
  handler: helloWorldWithExtraOutputs
});

outputinput@azure/functions からインポートして、そこから取得したバインディング定義のオブジェクトを http トリガーの関数 (handler) と一緒に extraOutputs, extraInputs として登録、という流れ。

その他諸々は上述のリンクをご参照くださいませ。

プロトタイプ

このリポジトリで公開中。

github.com

手順通りにやれば特に問題な動くことが確認できる。

注意 : Azure Functions 上にデプロイしてもまだ動かない

func コマンドの注意点

通常のインストール方法で入れた Azure Functions Core Tools の func コマンドから直接実行しちゃいけない。

WikiSetup の項目に

"func-cli-nodejs-v4": "4.0.4764": A preview build of the func cli that contains support for the new framework on the worker/host side of things

と書いてある通り、このプログラミング モデルでの実行には dev 版の Node.js Lauguage Worker が必要。
通常のインストール方法で入れた Azure Functions Core Tools 同梱の func を実行してしまうと、いつも通り function.json を探そうとして、当然見つからないので、結果「No job functions found.」となるだけ。

上記リポジトリの場合、この dev 版 Worker は package.jsondevDependencies にある func-cli-nodejs-v4@4.0.4764 に含まれているので、npm start 経由で func start を実行することで、dev 版 Worker を起動できる。

感想

だいぶ変わった印象だけど、関数登録処理自体を自前のコードでやるので、その処理の前(恐らく Worker が起動してエントリー ポイントがロードされた直後の状態)にオリジナルの処理を挟みやすくなる*1

まだ議論中の部分もありそうなので、いつ Public Preview、GA になるか、その時にはこの通り動くのかは不透明だけど、大きく変えようとしていることだけでも知っておいた方がよさそう。
他の言語も function.json 廃止の方向になるんだろうか。

*1:Top-level await はまだ使えないかも