在这种情况下,有状态服务指的是什么?
您是说构造对象时会产生副作用吗?
为此,一个更好的主意是拥有一种在应用程序启动时运行副作用的方法。而不是在构建过程中运行它。
也许您是说它在服务内部具有可变状态?只要不暴露内部可变状态,就可以了。您只需要提供一种纯(相对透明)的方法即可与服务进行通信。
继续讲第二点:
假设我们正在构造一个内存数据库。
class InMemoryDB(private val hashMap: ConcurrentHashMap[String, String]) {
def getId(s: String): IO[String] = ???
def setId(s: String): IO[Unit] = ???
}
object InMemoryDB {
def apply(hashMap: ConcurrentHashMap[String, String]) = new InMemoryDB(hashMap)
}
IMO,这不一定是有效的,因为如果您进行网络呼叫,也会发生同样的事情。虽然,您需要确保该类只有一个实例。
如果您使用的Ref
是cats-effect,那么我通常会flatMap
在入口点使用ref,因此您的课程不一定是有效的。
object Effectful extends IOApp {
class InMemoryDB(storage: Ref[IO, Map[String, String]]) {
def getId(s: String): IO[String] = ???
def setId(s: String): IO[Unit] = ???
}
override def run(args: List[String]): IO[ExitCode] = {
for {
storage <- Ref.of[IO, Map[String, String]](Map.empty[String, String])
_ = app(storage)
} yield ExitCode.Success
}
def app(storage: Ref[IO, Map[String, String]]): InMemoryDB = {
new InMemoryDB(storage)
}
}
OTOH,如果您正在编写依赖于有状态对象(例如多个并发原语)的共享服务或库,并且您不希望用户关心初始化什么。
然后,是的,必须将其包裹在效果中。您可以使用类似的方法Resource[F, MyStatefulService]
来确保一切均已正确关闭。或者只是F[MyStatefulService]
没有什么可关闭的。
delay
并返回F [Service]。例如,请参见IOstart
上的方法,它返回IO [Fiber [IO,?]]而不是普通光纤。