【发布时间】:2021-04-23 01:30:29
【问题描述】:
我有一个基于 Vapor 应用的非常简单的服务。该服务使用来自另一个服务系列的数据。显然,这只是 map 方法所针对的应用程序。
链中的所有回调都执行,但链中的最后一个EventLoopFuture 从未完成,导致我的服务无限期挂起。
此代码进行一次异步调用以获取会话 ID,然后使用该数据检查某人是否是特定组的成员。对其他服务的调用返回合理的值 - 目前第二次调用总是返回错误。
当我调用此方法时,所有回调都会按预期执行和运行。
请注意,在这段代码 sn-p 中,我已经“解开”了序列的各个阶段,以试图找出问题所在,但整体行为不受影响。
我尝试了许多不同的链排列,在适当的情况下使用flatMap、map 和flatMapError,而没有改变最终结果。
let authService = remoteApi.authServices();
// EventLoopFuture<String> with sessionId
let sessionIdFuture = authService.getSessionId(username: userName, password: password)
// EventLoopFuture<Bool> with whether the user is in a particular group
let gsFuture = sessionIdFuture.flatMap { sessionId -> EventLoopFuture<Bool> in
let groupMemberService = remoteApi.groupMemberServices()
return groupMemberService.personIsInGroup(sessionId: sessionId, groupId: groupId, userId: userId)
}
// EventLoopFuture<Bool> if the above has an error, just return false
let errorFuture = gsFuture.flatMapErrorThrowing { error in
// This executes successfully!
return false
}
// EventLoopFuture<String> with the return data
let returnFuture = errorFuture.flatMapThrowing { isMember -> String in
// This executes successfully!
let response = PersonIsMemberResponse(isMember: isMember)
if let json = self.encodeResponse(response) {
print(json) // {"isMember": false}
return json
} else {
throw Abort(.internalServerError, reason: "could not encode our own dang data type");
}
}.always { result in
// This executes!
do {
try remoteApi.shutdown()
} catch {
print(error)
}
}
gsFuture.whenComplete { result in
// This executes!
print("gsFuture complete!")
}
errorFuture.whenComplete { result in
// This executes!
print("errorFuture complete!")
}
returnFuture.whenComplete { result in
// This DOES NOT execute!
print("returnFuture complete!")
}
我看不到最后一个flatMapThrowing 是如何执行并返回一个值的,那么future 不完整。我错过了什么?
【问题讨论】:
-
我刚刚尝试了这段代码(所有服务调用都被删除了),它对我来说很好用。但让我们深入了解一下:你确定
try remoteApi.shutdown()没有阻塞吗?例如,您可以在该行之后添加print("still here")。如果它仍在运行,您介意描述remoteApi.shutdown()正在做什么。是否可能关闭 EventLoopGroup 或 Vapor 应用程序? -
哦,这是 Linux 还是 macOS?如果是 macOS,
sample YourBinaryName在卡住状态下的输出也会有所帮助。 -
我在这里发表评论是因为 SO 告诉我,如果你用问题“回答”这不是一个好的答案:)。
-
确实是阻塞的。看起来它在
AsyncHTTPClient上调用了syncShutdown()。我知道如果客户端在没有关闭被调用的情况下进行 deinit 会非常生气。我想我需要为该服务制定正确的生命周期。 (它是单独库的一部分。)无论如何,谢谢!如果你复制你的问题作为答案,我可以给你梦寐以求的复选标记。 -
酷!这个想法是你从 一个 EventLoopGroup 开始,然后将它重用于一切:Vapor、AsyncHTTPClient、你的 NIO 代码等......