SpannerがSessionを使い果たしてブロックした

コンテナ内で動くスケジューラが一定時間で動かなくなるバグを追っていた。最初はスケジューラが止まってしまうのかと予想していたが、ブロックしてずっと待っていただけだった。 スレッドダンプをとったらわかった。

"scala-execution-context-global-1802" - Thread t@1802
   java.lang.Thread.State: WAITING
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for <15b7d45> (a java.util.concurrent.SynchronousQueue$TransferStack)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:458)
        at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
        at java.util.concurrent.SynchronousQueue.take(SynchronousQueue.java:924)
        at com.google.common.util.concurrent.Uninterruptibles.takeUninterruptibly(Uninterruptibles.java:233)
        at com.google.cloud.spanner.SessionPool$Waiter.take(SessionPool.java:411)
        at com.google.cloud.spanner.SessionPool$Waiter.access$3300(SessionPool.java:399)
        at com.google.cloud.spanner.SessionPool.getReadSession(SessionPool.java:754)
        at com.google.cloud.spanner.DatabaseClientImpl.readOnlyTransaction(DatabaseClientImpl.java:62)
        at jp.co.cyberss.live.common.core.client.SpannerClient.withinReadOnly(SpannerClient.scala:42)
(略)

結論としてはtransactionをクローズしてなかっただけだった。。。

SpannerのSessionは枯渇した場合にデフォルトでブロックする。

https://github.com/GoogleCloudPlatform/google-cloud-java/blob/bebc2efedf0bb71c6a58fa043d02844f344824c8/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPoolOptions.java#L25

SpannerのAPIにはSingleUseとそうでないものがあり、前者は AutoClosingReadContext を継承しているので自動でcloseしてくれる。そうでないものは明示的にcloseを呼ばないといけない。

このへん。 https://github.com/GoogleCloudPlatform/google-cloud-java/blob/v0.26.0/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionPool.java#L166-L173

なおこの時点でのSpannerのAPIのバージョンは 0.25.0-beta(https://github.com/GoogleCloudPlatform/google-cloud-java/tree/v0.25.0/google-cloud-spanner/src/main/java/com/google/cloud/spanner)を使っていた。