在这种情况下,有状态服务指的是什么?
您的意思是在构造对象时它会执行副作用吗?
为此,一个更好的主意是在应用程序启动时有一个运行副作用的方法。而不是在施工期间运行它。
或者您可能是说它在服务内部拥有一个可变状态?只要不暴露内部可变状态,应该没问题。您只需要提供一个纯粹的(引用透明的)方法来与服务进行通信。
扩展我的第二点:
假设我们正在构建一个内存数据库。
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
from 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]
没有什么可以关闭的。