Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

リソースのクリーンアップをうっかり忘れたらAzure Service Bus接続上限に当たった話

技術本部 Sansan Engineering Unit Data Hubグループの茂木(@shinnopo_)です。普段はSansanのデータ統合プラットフォームであるSansan Data Hubの開発をしています。

今回は、リソースのクリーンアップをし忘れたことでAzure Service Busの同時接続数の上限に達してしまった問題と、その解決方法について紹介します。

背景

Sansan Data HubはC#で開発されています。マイクロサービスで構成されており、各サービスがキューでつながっている非同期メッセージングアーキテクチャです。そして、その非同期メッセージングを行うメッセージブローカーにはAzure Service Busを採用しています。

Sansan Data Hubのアーキテクチャに興味がある方は以下の記事を参考にしてください。 https://buildersbox.corp-sansan.com/entry/2023/02/16/110000

ある日、Service Busの同時接続数上限に引っかかるエラーが発生しました。このエラーは、特定の機能が大量の接続を生成してしまうことが原因で、サービス全体に影響を及ぼしました。

Exception while executing function: [FunctionName] <--- Cannot allocate more handles. The maximum number of handles is 4999. (QuotaExceeded).

エラーの原因

このエラーの主な原因は、Service Busへの送受信を行うSenderやReceiverなどのオブジェクトが適切にクリーンアップされず、不要な接続が残ってしまうことでした。これにより、接続数が増え続け、最終的に上限に達してしまいました。

修正方法

クリーンアップは基本的なことですが、意外と見落としがちです。例えば、以下のコードではsenderのクリーンアップを忘れています。

var sender = serviceBusClient.CreateSender("example");
await sender.SendAsync(message);

この場合、以下のようにしてクリーンアップを実装します。

await using var sender = serviceBusClient.CreateSender("example");
await sender.SendAsync(message);

簡単な修正ではありますが、クリーンアップは意外と説明が省かれがちです。この記事では、ここを少しだけ深掘りしてみます。

DisposeとDisposeAsync

C#は、アンマネージドリソースのクリーンアップを行うためにdisposeパターンの実装を行うのが一般的です。IDisposableとその非同期版であるIAsyncDisposableインターフェースを利用して実装します。つまり、IDisposableまたはIAsyncDisposableが実装されていれば、これを呼び出せばいいのです。

詳細はMicrosoft公式ドキュメント*1*2を参照してください。

usingとDispose

とはいえ、Disposeをいちいち呼び出すのは面倒ですよね。そこで一般的にはusingステートメントを使用します。usingステートメントは、IDisposableを実装しているオブジェクトの寿命を管理し、スコープを抜ける際に自動的にDisposeメソッドを呼び出します。これにより、リソースリークを防げます。

await usingとDisposeAsync

await usingステートメントは、前述したusingステートメントと同様、リソースのクリーンアップをする必要がある場合に実装します。usingとの違いはawaitを使用することで、非同期のクリーンアップが可能になります。await usingを使用する場合は、対象のオブジェクトにIAsyncDisposableを実装する必要があります。

終わりに

今回のエラーに遭遇したことで、改めてリソースのクリーンアップの重要性を認識しました。願わくば、すべてGCにやってもらいたいところですが、仕組み上仕方がないですね...。上記のようにusingステートメントやDisposeメソッドを活用することで、リソースリークを防ぎ、安定したシステム運用が可能になります。

© Sansan, Inc.