Swift NIO事件链未完成

Swift NIO事件链未完成,swift,swift-nio,Swift,Swift Nio,我有一个基于Vapor应用程序的非常简单的服务。该服务使用来自另一个服务系列的数据。显然,这正是map方法的应用类型 链中的所有回调都会执行,但链中最后一个EventLoopFuture永远不会完成,导致我的服务无限期挂起 这段代码进行一次异步调用以获取会话Id,然后使用该数据检查某人是否是特定组的成员。对其他服务的调用返回合理的值-当前第二个调用总是返回错误 当我调用这个方法时,所有回调都按预期执行和行为 请注意,在这段代码片段中,我“取消”了序列的各个阶段,试图揭示问题出现的地方,但总体行为

我有一个基于Vapor应用程序的非常简单的服务。该服务使用来自另一个服务系列的数据。显然,这正是
map
方法的应用类型

链中的所有回调都会执行,但链中最后一个
EventLoopFuture
永远不会完成,导致我的服务无限期挂起

这段代码进行一次异步调用以获取会话Id,然后使用该数据检查某人是否是特定组的成员。对其他服务的调用返回合理的值-当前第二个调用总是返回错误

当我调用这个方法时,所有回调都按预期执行和行为

请注意,在这段代码片段中,我“取消”了序列的各个阶段,试图揭示问题出现的地方,但总体行为不受影响

我尝试了许多不同的链排列,在适当的情况下使用
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!")
}
让authService=remoteApi.authServices();
//带有sessionId的EventLoopFuture
让sessionIdFuture=authService.getSessionId(用户名:用户名,密码:密码)
//EventLoopFuture与用户是否在特定组中有关
让gsFuture=sessionIdFuture.flatMap{sessionId->EventLoopFuture在
让groupMemberService=remoteApi.groupMemberServices()
返回groupMemberService.personIsInGroup(sessionId:sessionId,groupId:groupId,userId:userId)
}
//EventLoopFuture如果上面有错误,只需返回false
让errorFuture=gsFuture.FlatMapErrorSprowing{error in
//这将成功执行!
返回错误
}
//EventLoopFuture返回数据
让returnFuture=errorFuture.flatmapshowing{isMember->字符串插入
//这将成功执行!
让响应=个人成员响应(isMember:isMember)
如果让json=self.encodeResponse(响应){
打印(json)/{“isMember”:false}
返回json
}否则{
抛出中止(.internalServerError,原因:“无法编码我们自己的dang数据类型”);
}
}.总是{导致
//这执行!
做{
请尝试remoteApi.shutdown()
}抓住{
打印(错误)
}
}
gsFuture.whenComplete{导致
//这执行!
打印(“gsFuture complete!”)
}
errorFuture.whenComplete{结果为
//这执行!
打印(“errorFuture complete!”)
}
returnFuture.whenComplete{结果为
//这不会执行!
打印(“返回未来完成!”)
}

我不知道如何执行最后一个
flatmapshopping
并返回一个值,那么未来就不完整了。我遗漏了什么?

正如我们在评论中一起发现的,它看起来像是
尝试remoteApi。shutdown()
正在阻止任何进一步的事情发生。

我刚刚尝试了这段代码(所有的服务调用都被打断),它对我来说很好。但让我们深入了解一下:您确定
try remoteApi.shutdown()
没有阻塞吗?例如,您可以在该行之后添加一个
打印(“仍然在这里”)
。如果它仍在运行,请描述一下
remoteApi.shutdown()
正在做什么。它可能会关闭EventLoopGroup或Vapor应用程序吗?哦,这是Linux还是macOS?如果是macOS,则当处于卡住状态时,
sample YourBinaryName
的输出也会有所帮助。我在这里发表评论是因为这样告诉我,如果你用问题“回答”,这不是一个好答案:)。事实上,这是阻塞。它看起来像是在
AsyncHTTPClient
上调用syncShutdown()。我知道,如果客户在没有接到电话的情况下拒绝服务,就会非常生气。我想我需要为该服务制定正确的生命周期。(这是一个独立图书馆的一部分)无论如何,谢谢!如果你复制你的问题作为答案,我可以给你梦寐以求的复选标记。酷!我们的想法是,您只需要从一个EventLoopGroup开始,然后将其用于一切:Vapor、AsyncHTTPClient、NIO代码等等。。。