繁体   English   中英

如何在golang中处理和获取goroutines的响应

[英]How to Handle and get response from goroutines in golang

我已经在getPosition,getStatus和我的无人机重新路由中调用例程我正在调用我的main函数中的GetStatus,这个函数有func()处理流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)
    }

在通话结束后,我有这个代码,它应该每10秒返回一次成功

return c.JSON(500, failed or pass)

我期待一些东西返回到ui如果例程成功或失败当流式传输部分正在为响应而不是待处理或者其他api调用将不起作用。

如果你想知道在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)

我建议设置一个频道来接收来自go例程的事件。 在调用函数中,您可以在循环中侦听这些事件(可以包含您想要的任何信息),直到go例程自行关闭,表示失败。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM