swift EventLoopFuture导致`无效状态:无法写入消息`

agyaoht7  于 12个月前  发布在  Swift
关注(0)|答案(1)|浏览(60)

我正在使用grpc-swift和ClientInterceptor向请求添加一个auth令牌。我为send实现了delegate方法,如下所示

override func send(_ part: GRPCClientRequestPart<Request>, promise: EventLoopPromise<()>?, context: ClientInterceptorContext<Request, Response>) {
        
        guard case .metadata(var headers) = part else {
            return context.send(part, promise: promise)
        }
        
        let p = context.eventLoop.makePromise(of: String.self)
        p.completeWithTask {
            "My Token" // In reality this is actually an async function like `await myActor.idToken`
        }
        p.futureResult.whenSuccess { token in
            print(context.eventLoop.inEventLoop) // This returns `true`
            headers.add(name: "Authorization", value: "Bearer \(token)")
            context.send(.metadata(headers), promise: promise)
        }
    }

我需要从actor中读取值,这需要async/await来获取值,因此使用了创建一个promise,然后是p.completeWithTask
我面临的问题是,当这样做,然后调用context.send(_,promise:)是,我收到一个错误回来说Invalid state: unable to write message,在看文档,它说/// An invalid state was encountered. This is a serious implementation error.,我显然做了一些非常错误的,但对我的生活,我不知道是什么?
如果没有promise/future使用它,一切都很好。我不确定我是否正确使用了p.completeWithTaskp.futureResult.whenSuccess

plupiseo

plupiseo1#

我很确定你最后会重新排序信息。通常,gRPC请求/响应将是.metadata(...),然后是.message(...),最后是.end。顺序很重要。如果你不服从正确的命令,你就会进入非法状态。
因此,您可能会遇到以下情况:
1.你收到一个.metadata(...),你没有立即转发,因为你异步获得了auth令牌
1.您收到.message(...)并立即转发
1.(无关紧要,因为我们已经处于糟糕的状态)您完成了异步身份验证并转发了增强的.metadata(...)
你看现在是什么情况?您可能会在 * .metadata之前转发.message *,这是非法的,会使您进入该状态。
那你怎么解决这个问题呢?我认为你需要手动缓冲所有你收到的part,直到你设法得到增强的.metadata(...)。这不是难以置信的困难,但也有点烦人。
这个问题与你正在做的事情非常相似顺便说一句:https://github.com/grpc/grpc-swift/issues/1181
特别是@glbrntt回复中的这段
您还必须确保在拦截器中适当地缓冲了所有请求部分,以确保请求部分以正确的顺序发送(即:您可以在获取令牌的异步代码完成之前接收要发送的请求消息)。
我在gRPC Swift上提交了一些关于这个的bug:

相关问题