我正在尝试在 iOS 上的 React Native 中构建一个 gRPC 客户端。
对于上下文:不直接支持 gRPC 的 React Native 必须从 Swift 调用自定义的 Native Module,它会调用 gRPC 并返回值。
gRPC 服务器是一个本地编译的 goLang 模块,它使用该http2server
模块。我没有编写 gRPC 服务器,所以我无法更改它的代码。
看来 React Native 方法正在循环执行本机 gRPC 客户端调用,导致 Golang 的 http2Server 模块崩溃。
这个 gRPC 客户端调用是从按钮onPress()
事件调用的,而不是从循环调用的。我尝试将 gRPC 调用包装在超时测试中,以防止调用过快。
我的 Native 模块有一个如下所示的导出函数:
@objc(SwiftNativeGrpcClient) class SwiftNativeGrpcClient: NSObject {
// ...
@objc func swiftGetGrpcTest(
_ resolve: RCTPromiseResolveBlock,
rejecter reject: RCTPromiseRejectBlock
) {
print("SwiftNativeGrpcClient.swiftGetGrpcTest()")
// connect to gRPC channel if necessary
if (self.secureGrpcChannel == nil) {
self.createSecureChannel()
}
// out of paranoia, don't let this call be used less than
// once per second
if (getMilliSecondsSinceLastCall() < 1000) {
print("Method called to soon.")
reject("0", "Method called too soon", nil)
return
}
let grpcServiceClient = Service_ServiceName(channel: self.secureGrpcChannel!)
let testRequest: Service_TestRequest = Service_TestRequest()
// Service_TestResponse should contain a String:
// "gRPC response success"
let testResponse: Service_TestResponse
let testCall = grpcServiceClient.getTest(testRequest)
do {
try testResponse = testCall.response.wait()
print(testResponse)
} catch {
print("RPC method 'getInfo' failed \(error)")
return
}
// update the last call time to ensure this isn't being called
// more than once per second
self.lastCallTime = DispatchTime.now()
resolve(getInfoResponse)
}
// ...
}
</p>
我的 React Native 像这样调用原生模块:
const { SwiftNativeGrpcClient } = NativeModules;
export default function App() {
const nativeGrpcClient = useRef(SwiftNativeGrpcClient)
const [lastCallTime, setLastCallTime] = useState(new Date())
const rnGetGrpcTest = async () => {
try {
const currentTime = new Date()
console.log(`lastCallTime: ${lastCallTime}`)
console.log(`currentTime: ${currentTime}`)
const timeDiff = currentTime - lastCallTime
console.log(`timeDiff: ${timeDiff} ms`)
// Just checking... don't let this method
// be executed more than once per second
if (timeDiff > 1000) {
await nativeGrpcClient.current.swiftGetGrpcTest()
}
} catch (error) {
console.error(error.message)
}
setLastCallTime(currentTime)
}
// ...
}
Xcode 输出如下所示 </p>
- 看起来 gRPC 客户端正在对 gRPC 服务器进行多次调用。你会看到 React Native 模块发射器在崩溃之前发出了大约 20 次相同的响应
2021-12-01 15:23:56.400068+0200 testApp[13091:123303] [javascript] { output: 'SwiftNativeGrpcClient.swiftGetGrpcTest()\n' }
2021-12-01 15:23:58.698908+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.699576+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.700075+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.700606+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.701067+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.701596+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.702036+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.702726+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.704172+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.704766+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.705121+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.705497+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.705833+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.715472+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
panic: 2021-12-01 15:23:58.715856+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.716342+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.716751+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.717020+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.717247+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.717510+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.718216+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
close of closed channel
goroutine 24507 [2021-12-01 15:23:58.718544+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
running]:
2021-12-01 15:23:58.718827+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.719167+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
- Golang 的 http2Server 在
handlePing()
通过原生 Swift 模块向 React Native 返回响应后,在方法过程中崩溃。似乎 gRPC 连接已关闭,然后再次尝试关闭,http2server 无法正常处理
这是 Xcode 控制台日志:
2021-12-01 15:23:58.717247+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.717510+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
2021-12-01 15:23:58.718216+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
close of closed channel
goroutine 24507 [2021-12-01 15:23:58.718544+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
running]:
goroutine 24507 [2021-12-01 15:23:58.718544+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
running]:
2021-12-01 15:23:58.718827+0200 testApp[13091:123303] [javascript] Got output from Naive Module Emitter:
2021-12-01 15:23:58.719167+0200 testApp[13091:123303] [javascript] { output: '1638365038 [INF] test.go:3294 gRPC response success\n' }
google.golang.org/grpc/internal/transport.(*http2Server).handlePing(0xc00007a1c0, 0xc003c08090)
google.golang.org/grpc@v1.34.0-dev.0.20201021230544-4e8458e5c638/internal/transport/http2_server.go:680 +0x6d
google.golang.org/grpc/internal/transport.(*http2Server).HandleStreams(0xc00015d800, 0xc0029d0f68, 0x10a742005)
google.golang.org/grpc@v1.34.0-dev.0.20201021230544-4e8458e5c638/internal/transport/http2_server.go:494 +0x31f
google.golang.org/grpc.(*Server).serveStreams(0xc000499860, {0x10b916390, 0xc00015d800})
google.golang.org/grpc@v1.34.0-dev.0.20201021230544-4e8458e5c638/server.go:742 +0x114
google.golang.org/grpc.(*Server).handleRawConn.func1()
google.golang.org/grpc@v1.34.0-dev.0.20201021230544-4e8458e5c638/server.go:703 +0x34
created by google.golang.org/grpc.(*Server).handleRawConn
google.golang.org/grpc@v1.34.0-dev.0.20201021230544-4e8458e5c638/server.go:702 +0x405
CoreSimulator 757.5 - Device: iPhone SE (2nd generation) (ECBD797A-E2B4-49F2-9DD5-BC8FB95EFACC) - Runtime: iOS 14.5 (18E182) - DeviceType: iPhone SE (2nd generation)
当我使用完全相同的 Swift 代码创建一个测试项目,但没有 React Native 前端时,我没有遇到这种崩溃。React Native 以某种方式参与了崩溃行为,可能是由于 Native Module 功能的功能?
有谁知道如何防止这种循环发生?