Is the below code correct to work with cats effect and IO?
Should this be using a resource, if so, can someone help me as I haven't used resource before.
object AWS {
val client = AWSClientBuilder.defaultClient()
def blah(...): IO[Unit] = IO {
client.submitJob(new AwsRequest(....))
}
}
Technically not, since client
(and thus AWS) are shared mutable state.
However, the refactoring is not only using Resource
, but also not using a global object and passing down the dependency explicitly.
Like this:
// Make AWS an interface that defines the operations it provides.
trait AWS {
def foo(...): IO[Unit]
}
// In the companion object put a factory method that instantiates the resources.
object AWS {
def instance(...): Resource[IO, AWS] =
Resource
.make(IO(AWSClientBuilder.defaultClient))(client => IO(client.close()))
.map(client => new AWSImpl(client))
}
// Have a private implementation of the interface.
private[pckg] final class AWSImpl (client: AWSClient) extends AWS {
def blah(...): IO[Unit] = IO {
client.submitJob(new AwsRequest(...))
}
}
// Whatever was using AWS globally before now must require its dependency.
final class Domain(aws: Aws) {
def bar(...): IO[Unit] =
aws.foo(...)
}
// Assembly the dependency graph on the main.
final class Main extends IOApp.Simple {
override final val run: IO[Unit] =
Aws.instance(...).use { aws =>
val domain = new Domain(aws)
domain.bar(...)
}
}
This is a very general idea, don't follow blindly.