You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

grpc-swift ClientInterceptor用EventLoopFuture报Invalid state错误排查

问题原因分析

这个错误的核心是你在脱离Interceptor上下文的EventLoop线程中调用了context.send(_:promise:),导致gRPC的上下文状态失效。具体细节:

  • gRPC-Swift的ClientInterceptor的send方法绑定到特定EventLoop执行,所有与context相关的操作必须在这个EventLoop上完成。
  • 用async/await从actor获取Token时,异步任务可能被调度到其他线程/EventLoop,此时再调用context.send,原上下文已不在可操作状态,触发"Invalid state"错误。
  • 若创建EventLoopPromise时未使用context.eventLoop,而是用了其他EventLoop,也会导致跨线程操作上下文的问题。
正确实现方式

修复后的代码示例,核心是确保所有与context的交互都回到原EventLoop执行:

import GRPC

final class AuthTokenInterceptor<Request: GRPCRequest, Response: GRPCResponse>: ClientInterceptor<Request, Response> {
    private let tokenActor: TokenActor
    
    init(tokenActor: TokenActor) {
        self.tokenActor = tokenActor
        super.init()
    }
    
    override func send(_ request: Request, context: ClientInterceptorContext<Request, Response>) {
        // 1. 用context的EventLoop创建Promise,保证上下文一致
        let promise = context.eventLoop.makePromise(of: Void.self)
        
        // 2. 处理异步获取Token的逻辑
        promise.completeWithTask { [weak self] in
            guard let self = self else { return }
            // 异步获取Token
            let token = await self.tokenActor.getToken()
            
            // 3. 修改请求,添加认证Token到metadata
            var modifiedRequest = request
            modifiedRequest.metadata.add(
                name: "Authorization",
                value: "Bearer \(token)"
            )
            
            // 4. 切回context的EventLoop执行send操作
            try await context.eventLoop.perform {
                context.send(modifiedRequest, promise: promise)
            }
        }
        
        // 处理异步任务中的错误
        promise.futureResult.whenFailure { error in
            context.send(error: error)
        }
    }
}

// 示例Token Actor
actor TokenActor {
    func getToken() async throws -> String {
        // 模拟异步获取Token逻辑
        try await Task.sleep(nanoseconds: 1_000_000_000)
        return "your-auth-token"
    }
}
关键注意点
  • 必须用context.eventLoop创建Promise:避免跨EventLoop操作导致的状态不一致。
  • 异步操作后切回原EventLoop:通过context.eventLoop.perform确保context.send在正确线程上下文执行,这是解决"Invalid state"错误的核心。
  • 不要直接将自定义Promise传给context.send:context.send的promise参数是用来接收该send操作的结果,而非绑定你的异步Token获取任务,两者要区分开。

内容的提问来源于stack exchange,提问作者sbarow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 08:03:12