我在 ZIO 应用程序中使用 Doobie,有时会出现死锁(应用程序完全冻结)。如果我仅在一个内核上运行我的应用程序,或者达到与数据库的最大并行连接数,就会发生这种情况。
我的代码看起来像:
def mkTransactor(cfg: DatabaseConfig): RManaged[Blocking, Transactor[Task]] =
ZIO.runtime[Blocking].toManaged_.flatMap { implicit rt =>
val connectEC = rt.platform.executor.asEC
val transactEC = rt.environment.get.blockingExecutor.asEC
HikariTransactor
.fromHikariConfig[Task](
hikari(cfg),
connectEC,
Blocker.liftExecutionContext(transactEC)
)
.toManaged
}
private def hikari(cfg: DatabaseConfig): HikariConfig = {
val config = new com.zaxxer.hikari.HikariConfig
config.setJdbcUrl(cfg.url)
config.setSchema(cfg.schema)
config.setUsername(cfg.user)
config.setPassword(cfg.pass)
config
}
Run Code Online (Sandbox Code Playgroud)
或者,我在 Hikari ( config.setLeakDetectionThreshold(10000L))上设置了泄漏检测参数,但出现泄漏错误不是由于处理数据库查询所花费的时间。
我开始使用Scalaz 7 Validation和/或disjunction来处理可能失败的操作列表并管理它们的结果.
对于这种用例,有两个记录良好的案例:
1 /您想检查某些条件的列表,并累积每个错误(如果有的话).在这里,你总是走到列表的末尾,如果有任何错误,你就会失败作为全局结果.这是一个适用于工作的应用程序.
2 /您希望执行可能失败的几个步骤,并在第一个失败时停止.在这里,我们有一个单调,在Scala中很好地理解.
所以,我有两个在同一行中的其他用例,但似乎在任何先例都不是很好:我想处理一个步骤列表,可能失败,并累积错误和成功结果(例如:它是一个对文件进行修改的列表,可能会发生错误,因为这是外部世界,而成功是我希望以后保留的补丁.
两个用例的区别仅在于我想提前停止(在第一个错误上)或者到列表的末尾.
那么,那是正确的呢?
(写这个问题让我觉得它只是一个简单的foldLeft,是吗?我会让这里的问题验证,如果有人想知道的话)
ZIO( https://zio.dev/ ) 是一个 Scala 框架,其核心是数据ZIO[R, E, A]结构,其站点提供了以下三个参数的信息:
齐奥
的
ZIO[R, E, A]数据类型有三种类型的参数:
R- 环境类型。该效果需要类型为 的环境R。如果该类型参数为Any,则表示效果没有要求,因为您可以使用任何值(例如,单位值())运行效果。E- 故障类型。如果值为 type ,则效果可能会失败E。一些应用程序将使用Throwable. 如果此类型参数为Nothing,则表示效果不会失败,因为没有 Nothing 类型的值。A- 成功类型。使用 type 值可能会成功A。如果此类型参数为Unit,则表示该效果不会产生有用的信息,如果是Nothing,则表示该效果将永远运行(或直到失败)。
很容易得到什么A是:它是函数在名义情况下返回的值,即我们为函数编码的原因。
R是一种依赖注入 - 一个有趣的话题,但我们可以ZIO通过始终将其设置为Any(并且实际上IO[E, A] = ZIO[Any, E, A]在 lib 中有一个别名)来忽略它以使用它。
因此,它仍然E是用于错误的类型(著名的错误通道)。我粗略地认为这IO[E, A] …