Azure Functionsの関数実行時にエラーとなった場合のとりあえずの処置方法

今朝、南関テイオーの予想配信関数が実行失敗しており、その復旧作業を行いました。本エントリではその一部始終をまとめてみました。

原因を確認する

南関テイオーの予想配信関数は7:10(JST)に起動するようにTimer Triggerが設定されています。

Azure Functionsでは、関数ごとに「モニター」という項目があり、そこで実行ログを閲覧することができます。

まず実行ログになんらかの異常が吐き出されているだろうということで確認してみたところ、案の定、予想配信関数の実行時に、以下のようなエラーが出ていました。

Exception while executing function: Functions.getRace
Microsoft.Azure.WebJobs.Host.FunctionInvocationException : Exception while executing function: Functions.getRace ---> System.ApplicationException :       0 [unknown (0xFB4)] bash 4924 D:Program Files (x86)Gitbin..usrbinbash.exe: *** fatal error - Couldn't set directory to \?PIPE temporarily.
Cannot continue.

   at async Microsoft.Azure.WebJobs.Script.Description.ScriptFunctionInvoker.ExecuteScriptAsync(String path,String arguments,Object[] invocationParameters,FunctionInvocationContext context) at C:projectsazure-webjobs-sdk-scriptsrcWebJobs.ScriptDescriptionScriptScriptFunctionInvoker.cs : 114
   at async Microsoft.Azure.WebJobs.Script.Description.ScriptFunctionInvoker.InvokeCore(Object[] parameters,FunctionInvocationContext context) at C:projectsazure-webjobs-sdk-scriptsrcWebJobs.ScriptDescriptionScriptScriptFunctionInvoker.cs : 64
   at async Microsoft.Azure.WebJobs.Script.Description.FunctionInvokerBase.Invoke(Object[] parameters) at C:projectsazure-webjobs-sdk-scriptsrcWebJobs.ScriptDescriptionFunctionInvokerBase.cs : 95
   at async Microsoft.Azure.WebJobs.Host.Executors.VoidTaskMethodInvoker`2.InvokeAsync[TReflected,TReturnType](TReflected instance,Object[] arguments)
   at async Microsoft.Azure.WebJobs.Host.Executors.FunctionInvoker`2.InvokeAsync[TReflected,TReturnValue](Object instance,Object[] arguments)
   at async Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.InvokeAsync(IFunctionInvoker invoker,ParameterHelper parameterHelper,CancellationTokenSource timeoutTokenSource,CancellationTokenSource functionCancellationTokenSource,Boolean throwOnTimeout,TimeSpan timerInterval,IFunctionInstance instance)
   at async Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ExecuteWithWatchersAsync(IFunctionInstance instance,ParameterHelper parameterHelper,TraceWriter traceWriter,CancellationTokenSource functionCancellationTokenSource)
   at async Microsoft.Azure…

予測

ひとまずリトライを何度か試してみたところ、全て同じ現象が発生。これは以前サポートに相談した時と同様にリソース枯渇が原因なのではないか?と予想。

復旧手順

復旧までの手順は以下の通りとなり、今回は無事に復旧することができました。

  1. 新しいFunctions Appリソースを作成する(今回はリージョンの問題ではないので同一リージョンでOKだった)
  2. アプリケーション設定(環境変数)を新しいFunctions Appリソースにコピペする
  3. 従来のFunctions Appリソースを停止する(重複起動を防ぐ)
  4. 新しいFunctions App側でデプロイオプションを設定する(ここで関数のソースコードがデプロイされる)
  5. 関数を実行する

特に4の手順が実行できるよう、bitbucketなどを利用してgitレポジトリ連携をしておくことが、手早い復旧をする上で肝要と言えます。

まとめ

Functions App(特に従量課金プラン)においては、リソース枯渇による関数実行の失敗がありえます。これはクラウドサービスを活用する以上、付いて回る類の問題と言えるのではないでしょうか。

そのような問題を乗り越えるためには、最初から「壊れてもすぐ直せる」ようにシステムを作っておくことが大事だと考えます。

Azure FunctionsでqueueTriggerのスロットリングをする

Azure Functionsを使った以下のようなサイト巡回の仕組みについて、是非とも気をつけたい箇所がありましたので、共有です。

このような特定のサイトを巡回する仕組みを作るとき、巡回先のサイトに対して秒間10リクエストくらいの比較的高密度なリクエストを送ることは、普通に考えると相手先のシステムにとって迷惑であろうと想像がつくことでしょう。

このような場合、リクエスト密度を軽減するために、並列リクエスト数の制限を行ったり、リクエストとリクエストの間にクールダウンを設けたりすることがあります。

クールダウンについては適宜sleepを入れるなどの対応をすることで、一応相手先に対するリクエスト密度の軽減が見込めることでしょう。しかし、並列リクエスト数の制限を行わないことには、ひっきりなしにリクエストを投げることになりかねません。

Queue Triggerにおけるジョブの並列処理数調整

今回例に挙げた構成の場合、巡回対象URLが多くなってくるとQueue Storageに一気にジョブが登録され、それらが片っ端から一気にQueue Triggerによって処理されてしまうことが問題となります。

上記の図にもある通り、Azure FunctionsにおけるQueue Triggerの並列処理数は、デフォルトでは16となっています。

この並列処理数を下げるためには、プロジェクト直下に以下のような内容でhost.jsonを作成し、デプロイする必要があります。

{
    "queues": {
        "batchSize": 3
    }
}

このqueues.batchSizeこそが、Queue Triggerの並列処理数設定となっています。

このように、相手先のシステムに過剰な負担を与えないようにすることができます。

まとめ

web巡回をAzure Functionsでシステム化しようとしている方は、是非ともQueue Triggerの並列処理数にも気をつけてください。

なお、host.jsonに関わる情報はgithubのazure-webjobs-sdk-scriptプロジェクトしか情報源を見つけることができませんでしたが、host.jsonをしっかり確認することで、Azure Functionsのチューニングが可能とも言えますので、要チェックです。

Azure Functions CosmosDB input bindingsを使う上でのコツ – バインド変数編

さて、今度はバインド変数に関する躓きを共有します。

クエリエクスプローラとFunctions経由との間でクエリの結果が異なる???

例えば以下のようなクエリをCosmosDBに投げるとします。

SELECT c.id FROM c WHERE CEILING(c.age / 10) * 10 = 30

クエリエクスプローラでは以下のような結果が得られました。

[
    {
        "id": "user-123"
    },
    {
        "id": "user-124"
    },
    {
        "id": "user-133"
    }
]

今度はクエリの30に当たる箇所を{generation}として、sqlQueryに設定します。

SELECT c.id FROM c WHERE CEILING(c.age / 10) * 10 = {generation}

こんな感じですね。そしてFunctions側でQueue Storageトリガーを使って以下のようなジョブを受け取ります。

{"generation": 30}

この時、Functionsで受け取れるCosmosDB inout bindingsの結果は以下のようなものとなります。

[]

すっからかんですね。。。一体どういうことでしょう。

理由

初めて知った時には非常に驚きましたが、どうやら各bindingsにわたってくる値は文字列としてキャストされてしまうっぽいということです。

本当は以下のように展開してほしいのですが。。。

SELECT c.id FROM c WHERE CEILING(c.age / 10) * 10 = 30

こんな感じになってしまうということです。

SELECT c.id FROM c WHERE CEILING(c.age / 10) * 10 = "30"

これは厄介ですね。。。。

対処

これを回避するには、クエリの方で強制的に数値に置き換えてやればよいのですが、CosmosDBのビルトイン関数には数値へのキャストをしてくれるものがありません。

そこで登場するのがユーザ定義関数(User Defined Function/UDF)です。

CosmosDBでは、javascriptを使ってユーザが関数を定義することができるのです。

CosmosDBのブレードにあるスクリプトエクスプローラというメニューから、UDFの定義ができます。

UDF開発画面

上記画像のような関数を定義してやり、sqlQuery側を以下のように変更すると、無事に期待した結果が得られます。

SELECT c.id FROM c WHERE CEILING(c.age / 10) * 10 = udf.ConvertToNumber({generation})

このほか、時刻にまつわる関数などもCosmosDBにはビルトインでは存在しませんが、このようなUDFを作って対応することが可能です。

CosmosDBのUDFは非常に強力な機能ですので、是非とも有効に活用していきたいものですね。

元ネタ:https://stackoverflow.com/questions/44916811/difference-among-the-azure-cosmosdb-query-explorers-results-and-the-azure-funct/44918767#44918767

Azure Functions CosmosDB input bindingsを使う上でのコツ – 余剰演算子編

先日あたりからAzure FunctionsのCosmosDB input bindingsを使っていて、いくつかはまりどころのような挙動に出くわしましたので、その説明と対処法を紹介していきます。

sqlQueryで剰余演算子(Modulation Symbol)がそのまま使えない

例えば以下のようなQueryをCosmosDBに投げるとします。

SELECT c.id FROM c WHERE c.level % 20

このクエリを直接クエリエクスプローラで実行する場合、期待する結果が得られます。

ところがこのクエリをAzure FunctionsのCosmosDB input bindingsにsqlQueryとして指定した場合、以下のようなエラーがでてしまい、期待した動作をしません。

2017-07-05T16:45:43.113 Exception while executing function: Functions.MyFunction. Microsoft.Azure.WebJobs.Host: The '%' at position 34 does not have a closing '%'.

理由

実はsqlQueryの仕様として、%というのはアプリケーション設定の値を参照するために使う記号でして、%myappSetting%のような感じで使うものだったんですね。

そのため、単独で%が登場すること自体があってはならない、と、そういうことが理由となっています。

対処

対処法の一つとして、アプリケーション設定値に%を設定して、それを使えばよい、というものがあります。

アプリケーション設定から値を設定する

上記画像のように、例えばmodulationsymbolというアプリケーション設定値を定義しておき、sqlQuery側では以下のように%%modulationsymbol%に置き換えることで、期待通りの結果を得ることができます。

SELECT c.id FROM c WHERE c.level %modulationsymbol% 20

あまりカッコよくはないですが、致し方がない感じはしますね。

元ネタ:https://stackoverflow.com/questions/44903632/sqlquery-of-documentdb-input-bindings-with-modulation-symbol-makes-functions-fa

Azure Functions Cosmos DB Bindingsの新機能sqlQueryを試してみた

Cosmos DB Binding

Azure Functions Cosmos DB bindingsというドキュメントが公開されていることに最近気がついたのですが、その中でも個人的に以前から密かに待望していた機能であるsqlQueryについて、とうとう公式に明記されました。

大変便利と思われるこの機能を早速試してみましたので、本エントリで紹介していきます。

なお、本エントリの前提知識として、以下のエントリを読んでおくことをお勧めします。

Azure DocumentDB inputを設定する

今回私が作った関数のfunction.jsonですが、DocumentDB inputの設定は以下のようになっております。よく見ると、sqlQueryに見慣れたSQLが記述されていますね。

これを標準エディタで見てみますと、以下のようになります。

sqlQueryの仕様

テーブル名を必ず指定する必要がある(ただし何でもOK)

気をつけなければいけない点として、フィールド名を指定する場合はテーブル名を指定する必要があるということです。

function.jsonでコレクション名を指定してあるため、テーブル名そのものは何でもOKであり、特に何らかの影響を与えるわけではありません。このため、慣例的にテーブル名をcとすることが多いようです。そのため、フィールド名nameを指定するためにはc.nameとする必要があります。

クエリバインド変数の指定方法

httpバインディングで受け付ける関数の場合、sqlQueryに対して{name}などとすることでクエリバインド変数を利用することが可能です。

例えば SELECT c.id FROM c WHERE c.type={type}というsqlQueryを指定した場合、getパラメータにtype=imageのように指定することで、typeimageであるドキュメントを全て持ってくることができます。

今回使ったデータ

今回の検証のために、あらかじめ別の関数を使ってCosmos DBに以下のようなドキュメントデータをいくつか登録しておきました。

関数のコーディング

普段ですとPerlやBashでコードを書いたりするのですが、今回はPHP7での実装事例を紹介します。

中身はこれしかありませんが、一応おさらいも兼ねて解説していきます。

1行目ですが、このコードはphpで動作するコードですので、Functionと言えど <?phpで開始する必要があります。

2行目ではfunction.jsonで指定したsqlQueryの結果を$messageに格納する処理を行っています。

getenvの引数に指定する文字列は、function.jsonで指定したnameと同じものを指定します。これによりgetenvはCosmos DBから取得したJSONデータを内包した一時ファイルのパスを返します。あとはfile_get_contentsで中身を取り出し、json_decodestdClassに復元してやることで、phpで自在に操作可能となります。

3行目はレスポンス処理を行っています。getenvでレスポンス用の一時ファイルパスを取得し、そこにjson_encodeしたデータをfile_put_contentsで書き込んでやるだけです。

実際にアクセスしてみる

以下は、GETパラメータにname=tagoをつけてリクエストを投げてみた結果です。

任意の絞り込みを行った結果を取得できていることがわかると思います。

まとめ

今回の検証で、Azure Functions + Cosmos DBを使ったSQLライクな問い合わせができることがわかりました。

ちなみにCosmos DBに対するクエリとして、既に一部の集計関数がサポートされています。ただし、GROUP BY句は現時点ではサポートしていません(かなりアツい要望は多数あるようです。私も欲しい)。

Azure Functionsのパフォーマンスに関する実験

昨日、ほんの出来心でMojoアプリをAzure Functionsで動かせたらどうだろうなどと考えてしまい、2時間弱くらいでMojo::Server::AzureFunctionsというものを作りました。

Mojo::Server::AzureFunctionsを作って使うまで

もともとAzure FunctionsのHTTP TriggerとHTTP output bindingをハンドリングするためのアダプタとして作ろうとあらかじめ決めており、Functions自体はリクエストごとにプロセスを起動する動作モデルであるため、これはCGIと同様であるとみなすことができました。

従って、既存のMojo::Server::CGIを参考に、環境変数の解析と入出力の調整だけでどうにかMojoアプリをAzure Functionsで動作させることに成功しました。

動作確認したソースコードはこちらのレポジトリに上げてあります。

苦しかった点

Mojoでは $c->render(json => {...}); とすることでJSONによるレスポンスを行うことができます。

ところが、Mojo::ServerMojo::Messageではrenderメソッドの第1引数に渡された値を一切検出できません。

そのため、レスポンスのContent-TypeやContentそのものを検証して、ContentがJSON Stringであるかどうかを検証する必要があり、そうしなければAzure FunctionsのHTTP output bindingでは単なる文字列として判別されてしまい、<string>{"message": "hello"}</string> という感じの残念なレスポンスを返してしまうことになるのです。

これを回避するコードがココでして、Contentが{で始まっていれば多分JSONだろうとみなし、evalで囲った中でdecode_jsonをかけるという非常に野蛮な方法で対応したことがお分かり頂けると思います。

実際に動作させてみた

さて、Azure Functionsにデプロイして実際に動作させてみた結果をお見せします。

Azure Functionsの大変便利な機能の一つとして、関数ごとにレスポンスにかかった時間のモニターをすることができる、その名もずばり「モニター」という機能があります。今回はそこで記録された動作速度を見ていただきたいと思います。

一番右側の丸括弧で囲われた値がレスポンスまでにかかった時間です。平均およそ23秒ほどでしょうか。これは遅いですね!

なぜ遅いか?

実は遅い理由は非常に単純でして、Mojoliciousをuseするコストがあまりにも高いことが挙げられます。これはMojoliciousが悪いわけでもありませんし、もちろんAzure Functionsが悪いわけでもありません。

どういうことかというと、そもそもAzure Functionsには非常にシンプルなものがデプロイされることが期待されています。Webアプリケーションフレームワークのような複雑なコードは毎回ロードするだけでもコストがかかりますので、当然のようにレスポンスまで時間がかかるのです。

証拠

例えば関数内のrun.shの内容が以下のように非常に単純なものだったとします。

perl -MJSON::PP -le 'print encode_json({message => "Hello, World!"})' > $res

その場合は、以下のようなレスポンス速度を実現することができるのです。

概ね0.5〜2秒程度でレスポンスを返すことができています。必要十分な速度と言えますね。

まとめ

Azure FunctionsでMojoアプリを動作可能にするMojo::Server::AzureFunctionsを作って、レスポンス速度を確かめてみました。

その結果わかったのは、Azure Functionsには複雑なコードをデプロイすべきではなく、徹底的にシンプルなコードをデプロイすることでその真価を発揮することができる、ということです。その先にはほぼ無限のスケーラビリティとメンテナンスフリーにほど近いシステムの実現があると私は思います。

Azure + Perl でサーバレスなジョブシステムを作る

Azure + Perl でサーバレスなジョブシステムを作る

※このエントリは Microsoft Azure Advent Calendar 2016 及び Perl Advent Calendar 2016 の10日目のエントリです。

どーも、わいとんです。

今日はタイトルの通り、Microsoft AzureとPerlでサーバレスなジョブシステムを作るまでの流れを紹介していきます。

Azure 及び Perl について

その前に、このエントリにはAzure及びPerl双方の大まかな知識があることと、手元の端末がMacOSXであることが前提になります。

念のため、それぞれざっくりした説明をしておきます(多分に私見が混じっておりますことをあらかじめご了承ください)。

Azure とは

Microsoft Azure(以下Azure)はMicrosoft社がサービス提供をしているクラウドサービスです。

仮想マシンやネットワークなどをはじめとしたIaaS、Web Appsを軸にしたPaaS、そしてMobile AppsやNotification HubsなどのSaaSが提供されており、近年Amazon Web ServicesやGoogle Cloud Platformと並んで、クラウド御三家 などと例えられたりします(主に僕が例えてます)。

Microsoftのサービスらしく、基盤技術としてはWindowsや.NET技術が中心となっていますが、同社は最近OSSへのコミットメントが大変著しく、AzureでもLinuxのサポートが行なわれているサービスが結構存在します。

なお当エントリは、既にMicrosoftアカウントをお持ちで、Azure Portalでのサービス操作が可能なことが前提となっています。また、各種費用については事前に料金計算ツールなどでご確認の上、ご自身の責任においてお試しください。

Perl とは

1987年にLarry Wall(ラリー・ウォール)によって公開されたスクリプト言語です。

今日LL(Lightweight Language)と呼ばれるプログラミング言語群の先駆けであり、過去にはCGIというWebアプリケーション提供手法と組み合わせたパラダイムで一世を風靡しましたが、ここ最近はPHPやRubyなどの登場により、シェアは漸減しているようです。

しかしながら、CPANを軸にしたエコシステムの存在によって拡張性が大変強力であり、かつ徹底した後方互換性の維持方針によって、古いソースコードでも安定稼働が期待できます。

近年はテストドリブンな開発手法や継続テストなどによるモダンかつ安定性を重視した開発手法が採用されることもあり、当エントリも「モダンな手法としてのサーバレスアーキテクチャ」をPerlで実現する、というところを重視したつもりです。

Azure上に環境を作る

前置きが長くなりましたが、ここからはスナップショット画像を交えて、Azure上への環境構築の様子を解説していきます。

リソースグループを作る

Azure Portal上で新しくリソースグループを作ります。

※リソースグループとは: Azureにある様々なサービスを、用途ごとにまとめておく枠組みです。詳しくはこちらのエントリを参照してください。

画面左側にある水色の立方体アイコンがあるので、これをクリックすると、リソースグループ一覧が表示されます。そこに「追加」というボタンがあるので押すと、リソースグループ名の入力とロケーションの選択を促されます。

これらの入力を終えて作成ボタンを押して少し待つと、以下のようにリソースグループの概要が示されます。

リソースグループができた様子

これでリソースグループの完成です。

Event Hubsをデプロイする

リソースグループの概要画面で「追加」ボタンを押すと、デプロイしたいサービスを選んだり検索できる画面になります。ここでは「event hubs」と検索窓に入力してあげると、以下のようにEvent Hubsが登場しますので、これを選択します。

event hubsを検索した様子

すると、以下のように概要説明が出てきますので、作成ボタンを押します。

event hubsを検索した様子

作成ボタンを押すと、以下のように料金体系の選択や名称の設定など、5項目について入力を求められます。

event hubsをデプロイする様子

なお、今回僕は以下のように設定しました(なんかでかいかも)。

event hubsの設定例

デプロイには数分かかることもあるので、コーヒーでも淹れながらのんびり待っていると良いかと思います。そのうち以下のような通知がベルマークのところに出てくるので、待ちましょう。

デプロイ完了の通知

デプロイが完了してからリソースグループの更新を行うと、以下のようにEvent Hubsがデプロイされていることが確認できます。

event hubsがデプロイされた様子

Event HubsにHubを追加する

続いて、実際にペイロードの受容部となるHubを追加します。

先ほど作成したEvent Hubsを選択すると、以下のような画面になりますので、「+Event Hub」ボタンを押します。

event hubsにHubを追加する様子

すると、以下のように設定項目が登場しますので、NameとPartition Count(今回は8にしました)を適宜設定し、Createボタンを押します。

Hubの設定

少し待つと、Event Hub作成完了通知が以下のように出てきます。

Hubの作成完了通知

これでHubの追加が完了しました。

追加したHubにSAS鍵を追加する

実際にHubに対してペイロードを受容してもらうためには、あらかじめ定められた鍵を以ってペイロードの送信を行う必要があります。この鍵を使ったやりとりのことをSAS(Shared Access Signature)と呼びます。

鍵を作るには、先ほど追加したHubの概要を開きます。下記の例では 「Event Hubs」をメニューから選択し、一番下の方にちらっと見えている「advent」という名のHubを選択する感じになります。

Event HubsのHub一覧

すると以下のような画面が出てきますので、メニューから「Shared Access Policy」(鍵マークのやつ)を選択します。

Hub概要

最初は見ての通りShared Access Policyが何も存在しません。ポリシーを新しく作る必要があるので、「Add」ボタンを押します。

SASポリシーの確認

新規作成するポリシーの名称及び権限設定(Claim)を要求されます。

SASポリシーの設定

名前は任意の文字列、権限は「Manage」を設定して「Create」ボタンを押すと、ポリシーが作成されます。

SASポリシーの確認、再度。

中身を見てみると、以下のように権限設定の確認、それと鍵と接続文字列がそれぞれPrimary, Secondaryと並んでいます。

とりあえず後で使うので、接続文字列を(Primary/Secondaryどちらでもいいので)コピーして、どこかにメモしておいてください。

Function Appをデプロイする

Event Hubsの準備ができたところで、次にFunction Appsの準備を進めます。

改めてリソースグループの概要に戻り、「追加」ボタンを押して「function app」と検索窓に入力します。すると、Function App が検索結果の一番上に出てくるので、これを選びます。

function app の検索結果

以下のように解説が出てきますが、とりあえず「作成」ボタンを押します。

function app の説明

設定を要求するブレードが登場しますので、以下の例を参考に各々埋めて「作成」ボタンを押してください。

function appの設定

しばらく待っているとデプロイが完了しますので、リソースグループの概要で「更新」ボタンを押すと、以下のように稲妻アイコンのApp Serviceが登場しています。これがFunction Appです。また、ストレージアカウントも一緒に作られます。

Function app 作った後のリソースグループ

Function Appに関数を追加する

早速、出来上がったFunction Appを見てみると、以下のようにデカデカと関数への早道と書かれた仰々しい画面が登場しますが、これはどうでもいいです。

Function Appの概要

とりあえずデカイやつはどうでもよくて、左側のメニューにある「新しい関数」を選択します。すると以下のように「テンプレートの選択」が登場します。

ここでいろんなテンプレートがあって目移りするかもしれませんが、僕としては男は黙ってBashという信条がございます故、言語にBashを選択します。

言語選択

すると・・・

おお、神よ!Bashを救いたまえ!

悲しいかな、選べるものが1つしかなく、しかも「Azure Queue Storage」をトリガーとした関数テンプレートしかないのです。

しかし!ここで諦めてはいけない! まず、そのままこのテンプレートを選択します。

すると、選択したテンプレートの下に以下のようなフォーム群が登場します。とりあえず関数名を簡単なものにして、そのまま「作成」ボタンを押してください。

設定が登場する

これでとりあえず関数がデプロイされました。ただ、このままではEvent Hubsとの連携ができていませんので、この後直していきます。

追加した関数の入力元にEvent Hubsを指定する

さて、出来上がった関数は以下のようになっています。

出来上がった関数(bash)

なるほど。シンプルですね。

次に、左側のメニューから「統合」を選択します。

関数の統合設定

先ほどのテンプレート設定みたいな画面が出てきましたが、右上にある「詳細エディター」を選択してください。

詳細エディター

詳細エディターというのは、トリガーや入出力をJSON形式で自力で設定するためのツールなのですが、ここで以下のように修正し、保存します。

編集後

変更した箇所は "type" の設定値が "queueTrigger" だったのを "eventHubTrigger" に変えただけです。

この状態で「標準エディタ」を選択すると・・・

標準エディタで見てみた図

トリガーの部分が「Azure Queue Storage」から「Azure イベント ハブ」に変わっていますね!

Event Hub接続をFunctions Appに設定する

今度は「イベント ハブ接続」の設定を行うため、上気した画面の右下にある「新規」リンクを選択します。すると下記のような画面になります。

標準エディタで見てみた図

最初は「結果はありません」と書かれていますね。その上にある「接続文字列の追加」を押してください。

Service Bus 接続の図

接続名は任意の文字列隣ます。、接続文字列ですが、ここで先ほどコピーしておいたEvent Hubの接続文字列を貼り付けます。

ここまでやったら「OK」ボタンを押します。

イベントハブ接続が確立した図

ご覧の通り、イベントハブ接続の設定ができました。

クライアント側の実装を作る

さて、ここまででようやくAzure側の設定が完了しました。あとはクライアント側のコード実装を行い、ペイロードを投げ込むだけです。

ところで皆さん、PerlでEventHubsにペイロードを信するための方法をご存知でしょうか?

おそらくほとんどの方はご存知ないと思いますが、Net::Azure::EventHubsというモジュールがCPANにリリースされていて、これを使うと簡単にEventHubsにペイロードを送信することができます。なお、Net::Azure::EventHubsを作ったのは です。

Net::Azure::EventHubsを導入する

それでは cpanm あるいは cpm を使ってNet::Azure::EventHubsをインストールしてみましょう。

  • cpanmの場合

    $ sudo cpanm Net::Azure::EventHubs

  • cpmの場合

    $ sudo cpm install -g Net::Azure::EventHubs

これでインストールに成功すると思います。

スクリプトを書く

では実際にペイロードを送信するプログラムを書いてみます。

use strict;
use warnings;
use Net::Azure::EventHubs;

my $hub = Net::Azure::EventHubs->new(
    connection_string => 'Endpoint=sb://...',
);

my $req = $hub->message({
    name => 'ytnobody',
    age  => '36',
    fav  => [qw/Gyoza Curry Lucky-Pierrot/],
});
$req->do;

connection_string はご自身の環境に合わせて変更してください。

実際にペイロードを送信してみる

これをbashで実行すると、下記のgifのようになります。

実際にペイロードを送ってみる

ウル技(ウルテク)

さらにもう一歩Perlを推し進めたウル技を披露します。

Function AppでPerlを使ってペイロードを処理する

Azure側の関数のコードを以下のようにすることで、関数記述言語として、なんとPerl(v5.22.0)が利用可能です!!!!

まず run.sh は以下のように。

直接受ける側のbashコード

そして新しく worker.pl を作り、以下のようなコードにします。

worker.pl

非常に簡単なコードですね。これは run.sh で受けたペイロードをそのまま worker.pl に横流しして、そのままデバッグログに出力するだけの仕組みです。

これを動かすと、こうなります・・・!

worker.plをFunction Apps上で動かす

Azure Function AppはPerlが動くぞ!すごい!!

まとめ

  • AzureとPerlは協調できる!
  • Net::Azure::EventHubs を作ったぞ!
  • Azure Function App はPerlも使えるぞ!

最後に

このエントリは YAPC::Hokkaido 2016 SAPPORO参加しながら執筆しました。次回のYAPC::Japanは関西での開催らしいです。

Net::Azure::EventHubs – A Client Class for Azure Event Hubs – metacpan.org

Net::Azure::EventHubs – A Client Class for Azure Event Hubs – metacpan.org