最近、Azure Functionsのお勉強をチマチマと始めました。色々と分からないことが多かったのでお勉強メモをまとめて記します。
どこまで続くかわからないお勉強メモ。今日は11回目です。今回はQueue Triggerの利用について深掘りしてみます。過去のものは以下を参照。
- Azure Functionsのお勉強メモ(1)TypeScriptでチュートリアルを実施する - miyohide's blog
- Azure Functionsのお勉強メモ(2)Spring Cloud FunctionでHTTP Triggerを実装する - miyohide's blog
- Azure Functionsのお勉強メモ(3)Spring Cloud FunctionでTimer Triggerを実装する - miyohide's blog
- Azure Functionsのお勉強メモ(4)RubyでHTTP Triggerを実装する - miyohide's blog
- Azure Functionsのお勉強メモ(5)カスタムハンドラーを使ってRubyでTimer Triggerを実装する - miyohide's blog
- Azure Functionsのお勉強メモ(6)Blob Storage出力バインドを使ってBlobにファイルを出力する - miyohide's blog
- Azure Functionsのお勉強メモ(7)Blob Storage出力バインドを使ってBlobにファイルを出力する その2 - miyohide's blog
- Azure Functionsのお勉強メモ(8)Blob Storage出力バインドを使ってBlobにファイルを出力する その3 - miyohide's blog
- Azure Functionsのお勉強メモ(9)Blob Storageにファイルが登録された時に処理を実行する(未完成) - miyohide's blog
- Azure Functionsのお勉強メモ(10)Blob Storageにファイルが登録された時に処理を実行する(Queue利用編) - miyohide's blog
Queueにメッセージを送る
テスト用にQueueにメッセージを送るプログラムを以下の記事で作成しました。
記事ではAzuriteで作成したエミュレーター用の記述ですが、以下のように少し書き換えてやればAzure上でのQueueに対してデータを送ることができます。
# 省略 client = Azure::Storage::Queue::QueueService.create( storage_account_name: ストレージアカウント名, storage_access_key: アクセウスキー, storage_queue_host: "https://ストレージアカウント名.queue.core.windows.net/" ) # 省略
上記記事の初出時は、メッセージ送付を
client.create_message(キュー名, "test message #{index}")
としていましたが、これではAzure FunctionsのQueue Triggerにて以下のエラーが発生しました。
Unable to translate bytes [B5] at index 0 from specified code page to Unicode.
これを解決するには、メッセージをBase64でエンコードしてあげれば良いです。Rubyのコードで書けば以下の通り。
client.create_message(キュー名, Base64.encode64("test message #{index}"))
多くのQueueを送ったときにNullPointer Exceptionが発生する(未解決)
上記のプログラムでQueueに多くの(といっても100件ぐらい)メッセージを送ると以下のメッセージがでて処理が失敗しました。
Result: Failure Exception: NullPointerException: Stack: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.base/java.lang.reflect.Method.invoke(Unknown Source) at com.microsoft.azure.functions.worker.broker.JavaMethodInvokeInfo.invoke(JavaMethodInvokeInfo.java:22) at com.microsoft.azure.functions.worker.broker.EnhancedJavaMethodExecutorImpl.execute(EnhancedJavaMethodExecutorImpl.java:55) at com.microsoft.azure.functions.worker.broker.JavaFunctionBroker.invokeMethod(JavaFunctionBroker.java:57) at com.microsoft.azure.functions.worker.handler.InvocationRequestHandler.execute(InvocationRequestHandler.java:33) at com.microsoft.azure.functions.worker.handler.InvocationRequestHandler.execute(InvocationRequestHandler.java:10) at com.microsoft.azure.functions.worker.handler.MessageHandler.handle(MessageHandler.java:45) at com.microsoft.azure.functions.worker.JavaWorkerClient$StreamingMessagePeer.lambda$onNext$0(JavaWorkerClient.java:92) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) at java.base/java.util.concurrent.FutureTask.run(Unknown Source) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.base/java.lang.Thread.run(Unknown Source) Caused by: java.lang.NullPointerException at org.springframework.cloud.function.adapter.azure.FunctionInvoker.handleRequest(FunctionInvoker.java:117) at com.github.miyohide.QueueHandler.queueHandler(QueueHandler.java:17) ... 16 more
正直、この原因はわからなかったので、対処療法を行います。
対処療法としては以下二つを試しました。
- batchSizeを1にする
- batchSizeを2以上にしつつ、visibilityTimeoutを設定する
以下ドキュメントに書かれている通りのことをやっただけです。
batchSizeを1にすると1つのインスタンスで並行に動くことは無くなります。どうしても並行に動かしたいと言うことであれば、NullPointerExceptionが発生することは受け入れて、リトライで問題なければOKというスタンスでも良いかもしれません。動かすものによるかと思いますが、今回のサンプルではhost.json
を以下のようにしました。
{ "version": "2.0", "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", "version": "[1.*, 2.0.0)" }, "extensions": { "queues": { "visibilityTimeout": "00:00:05", "batchSize": 5 } } }
すると、1回目では失敗したメッセージが2回目では正常に処理できていることを確認できました。
1回目の処理。NullPointerExceptionが発生しています。
2回目の処理。特に例外は発生していません。