Reputation: 751
My Akka actor acquires some resources, which should be released after jobs are done, as shown by code snippet below.
The issue is, how to make sure the resources will be released in case of exceptions.
The first idea occurred to me is to assign the acquired resources to a var
, and release them in def postStop()
hook as a safeguard.
As this is a such common requirement, I'm wondering if there's any best practice to this?
override def receive: Receive = {
case FILEIO(path) => {
val ios = fs.create(new Path(path))
// ios.read/write ..
// exception could occur
ios.close()
}
}
Upvotes: 0
Views: 356
Reputation: 1240
If you use scala 2.13 you can try scala.util.Using. It will close the resource automatically even if an exception occurs.
val resultTry = Using(fs.create(new Path(path))) { ios =>
// ios.read/write ..
// exception could occur
}
resultTry match {
case Success(ioOperationsResult) => ...
case Failure(ioException) => ...
}
Also, you should separate blocking IO operations from the akka dispatcher.
Upvotes: 1
Reputation: 19517
Use Akka Stream's File IO sinks and sources. The FileIO
tools use actors under the covers, transparently close resources when errors occur, and run on a dedicated dispatcher. The latter is important because blocking IO operations should be isolated from the rest of the system. A simple example from the documentation:
import akka.stream.scaladsl._
val file = Paths.get("example.csv")
val foreach: Future[IOResult] = FileIO.fromPath(file).to(Sink.ignore).run()
Upvotes: 1
Reputation: 7275
I think you should reconsider using actors for heavy IO access. Given that you're using a default dispatcher, you might block it with IO operations and this will slow down the whole actor system.
If you still wish to proceed, recommend doing following
override def receive: Receive = {
case FILEIO(path) => {
val ios = fs.create(new Path(path))
try {
// ios.read/write ..
// exception could occur
} finally {
ios.close()
}
}
}
Alternatively, extract your IO work into async context, like Future
that should be executed in a dedicated execution context and use pipeTo
pattern to process results with an Actor.
Upvotes: 0