-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
I noticed after working on some code that my Spanner service was throwing a TimeoutException after calling closeAsync on it with a timeout on the get. I tracked it down to a stray ReadContext that I created in my code but never consumed or closed. If a timeout isn't set when dereferencing the future then it doesn't seem to ever return.
This is a minimal example in Clojure, but you should be able to get the gist of it. The important part is that a ReadContext is created but never closed.
(let [ ;; setup spanner
options (.. (SpannerOptions/newBuilder)
(build))
service (.getService options)
db (DatabaseId/of (.getProjectId options) "deps-dev" "deps-dev")
clientProject (.. service (getOptions) (getProjectId))
db-client (.getDatabaseClient service db)]
;; create a ReadContext
(.singleUse db-client)
(.get (.closeAsync ^Spanner service) 3 TimeUnit/SECONDS))
;; throws a j.u.c.TimeoutExceptionI realise that ReadContext is an AutoCloseable, but I found the behaviour a little surprising still. I'm not sure what (if any) changes could/should be made here, but I thought I'd raise the issue as I didn't see anything about this documented in the ReadContext javadoc except for maybe this comment "TODO(user): Add logging and tracking of leaked sessions." on closeAsync. A few options I can see:
- Do nothing. It's an autocloseable and if you don't close it then it's on you.
- Log about the leaked ReadContext and close anyway
- Return something from the future instead of nil
- Document in
closeAsyncthat it should be dereferenced with a timeout to prevent hangs (good practice in general) - Document in ReadContext that not closing it will lead to timeouts on closing the Spanner service.