我在goPosition,getStatus中调用了go例程,并为无人机重新路由。目前,我正在我的主要函数中调用go GetStatus,该函数具有gofunc()函数,该函数处理用于流式处理grpc和sse的事件。
当前这是我的代码,我尝试过
func GetPositionContext(ctx context.Context, uav pb.UAVControllerClient, uavID *pb.UAVID, projectID string) {
log.Printf("getPosition start")
stream, err := uav.GetPosition(ctx)
if err != nil {
fmt.Printf("ERROR getPosition:%s", err.Error())
}
streamID, eventName := EventsSubscribe(projectID, uavID.Aircraft, "get_position")
position := make(chan models.DronePosition)
// 受信ループ開始
go func() {
fmt.Print("start getPosition loop")
for {
msg, err := stream.Recv() // msg UAVPosition
if err == io.EOF {
// read done.
fmt.Print("start getPosition loop closed")
close(position)
return
}
if err != nil {
log.Fatalf("Failed to receive getPosition : %v", err)
close(position)
return
}
// log.Printf("Position point[%s](%f, %f, %f) H:%f", uavID.Aircraft, msg.Latitude, msg.Longitude, msg.Altitude, msg.Heading)
wayPoint := models.WaypointItem{
Latitude: msg.Latitude,
Longitude: msg.Longitude,
Altitude: msg.Altitude,
Heading: msg.Heading,
}
dronePosition := models.DronePosition{
Name: uavID.Aircraft,
ItemParameter: wayPoint,
}
// publish to eventgo
publishNotif(dronePosition, streamID, eventName)
return
}
}()
startMsg := pb.UAVControllerPositionRequest{
UavID: uavID,
Instruction: true,
Interval: 2,
}
fmt.Print("send getPosition start")
if err := stream.Send(&startMsg); err != nil {
log.Fatalf("Failed to send getPosition: %v", err)
}
<-position
stream.CloseSend()
fmt.Print("end of getPosition")
}
这是我调用此功能的部分
go utils.GetPosition(ctx, uavService, &uavID, projectID)
我想从go func获得返回值,例如,如果一切在grpc服务器中都工作正常,没问题,我应该返回200成功,如果失败则返回500。
for {
time.Sleep(time.Duration(60) * time.Second)
}
通话后,我有此代码,每成功发送一次代码应成功返回
return c.JSON(500, failed or pass)
如果流例程正在处理响应以使其未挂起,或者其他api调用无法正常工作,则go例程成功或失败时,我希望可以返回到ui。
答案 0 :(得分:1)
如果您想知道在GetPositionContext内部处理go func()时是否出错,则可以执行以下操作。我修改了所有错误以冒出气泡,而不是调用log.Fatal。顺便提一句,推迟stream.CloseSend()
可能是明智的选择,但是我缺少上下文,这不在问题的讨论范围之内。
我尽力理解这个问题,但是如果我错过了什么,请告诉我!
已对代码进行了修改,以直接使GetPositionContext中的错误冒泡,而不是调用log.Fatal。此外,如果go func()中存在错误,它将通过通道发送回GetPositionContext,然后返回给调用方。
func GetPositionContext(ctx context.Context, uav pb.UAVControllerClient, uavID *pb.UAVID, projectID string) error {
log.Printf("getPosition start")
stream, err := uav.GetPosition(ctx)
if err != nil {
return fmt.Errorf("ERROR getPosition: %v", err.Error())
}
streamID, eventName := EventsSubscribe(projectID, uavID.Aircraft, "get_position")
errC := make(chan error)
// 受信ループ開始
go func() {
fmt.Print("start getPosition loop")
for {
msg, err := stream.Recv() // msg UAVPosition
if err == io.EOF {
// read done.
fmt.Print("start getPosition loop closed")
close(errC)
return
}
if err != nil {
errC <- fmt.Errorf("Failed to receive getPosition : %v", err)
return
}
// log.Printf("Position point[%s](%f, %f, %f) H:%f", uavID.Aircraft, msg.Latitude, msg.Longitude, msg.Altitude, msg.Heading)
wayPoint := models.WaypointItem{
Latitude: msg.Latitude,
Longitude: msg.Longitude,
Altitude: msg.Altitude,
Heading: msg.Heading,
}
dronePosition := models.DronePosition{
Name: uavID.Aircraft,
ItemParameter: wayPoint,
}
// publish to eventgo
publishNotif(dronePosition, streamID, eventName)
// Did you mean to return here? The for loop will only ever execute one time.
// If you didn't mean to return, then remove this close
close(errC)
return
}
}()
startMsg := pb.UAVControllerPositionRequest{
UavID: uavID,
Instruction: true,
Interval: 2,
}
fmt.Print("send getPosition start")
if err := stream.Send(&startMsg); err != nil {
return fmt.Errorf("Failed to send getPosition: %v", err)
}
err = <- errC
stream.CloseSend()
fmt.Print("end of getPosition")
return err
}
如果要异步调用此函数,但仍想知道是否有错误,则可以执行以下操作。
errC := make(chan error)
go func() {
errC <- GetPositionContext(..........)
}()
// Do some other stuff here
// Until you need the result
err := <- errC
// ... and Eventually when you want to return the success or failure as JSON
if err != nil {
return c.JSON(500, failed)
}
return c.JSON(500, pass)
答案 1 :(得分:0)
我建议设置一个通道以接收来自go例程的事件。在调用函数中,您可以循环侦听这些事件(其中可以包含您想要的任何信息),直到go例程自身关闭(表明失败)为止。