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

Go协程中调用GCP Compute Operation时net/http Client为nil问题

GCP Go SDK compute.Operation协程调用Wait时http.Client为nil的问题

问题现象

使用GCP Go SDK的compute.Operation包时,仅在Go协程中调用op.Wait(ctx)会触发net/http(*Client)指针为nil的panic,导致请求失败。同步调用Wait则无异常,调试单步执行会快速panic,全速运行时成功请求数不稳定,关闭Go垃圾回收器也无法解决。

代码示例

import (
    "context"
    "sync"

    compute "cloud.google.com/go/compute/apiv1"
    computepb "google.golang.org/genproto/googleapis/cloud/compute/v1"
)

func WaitForImages(op *compute.Operation, wg *sync.WaitGroup) {
    defer wg.Done()
    op.Wait(ctx) // 原代码存在ctx未传入的作用域问题
    // 镜像创建完成后的操作
}

func TakeImage(context context.Context, req *computepb.InsertImageRequest, wg *sync.WaitGroup) {
    c, err := compute.NewImagesRESTClient(ctx)
    defer c.Close() // 问题根源:函数返回时立即关闭客户端
    if err != nil {
        return
    }
    op, err := c.Insert(ctx, req)
    if err != nil {
        return
    }
    wg.Add(1)
    go WaitForImages(op, wg)
}

func Main() {
    images := []string{/* 镜像列表 */}
    var wg *sync.WaitGroup = &sync.WaitGroup{}
    ctx := context.TODO()
    for _, img := range images {
        img := img
        req := &computepb.InsertImageRequest{
            Project: myProject,
            ImageResource: &computepb.Image{
                Name:       &img,
                SourceDisk: &img,
            },
        }
        TakeImage(ctx, req, wg)
    }
    wg.Wait()
}

报错信息

4  0x00000000006ee4d7 in net/http.(*Client).deadline
         at /usr/lib/go-1.19beta1/src/net/http/client.go:188
     5  0x00000000006f1105 in net/http.(*Client).do
         at /usr/lib/go-1.19beta1/src/net/http/client.go:599
     6  0x00000000006f0f4f in net/http.(*Client).Do
         at /usr/lib/go-1.19beta1/src/net/http/client.go:581
     7  0x00000000006f08a5 in net/http.(*Client).Get

问题原因

compute.Operation实例持有创建它的ImagesClient的内部引用,而TakeImage函数中使用defer c.Close()会在函数返回时立即关闭客户端。此时协程中的op.Wait还在运行,依赖的客户端已被关闭,其内部的http.Client被置为nil,最终触发panic。

解决方案

调整客户端的生命周期,确保在op.Wait完成后再关闭客户端,将客户端传递到协程中统一管理:

import (
    "context"
    "sync"

    compute "cloud.google.com/go/compute/apiv1"
    computepb "google.golang.org/genproto/googleapis/cloud/compute/v1"
)

func WaitForImages(op *compute.Operation, client *compute.ImagesClient, wg *sync.WaitGroup) {
    defer func() {
        client.Close() // Wait完成后关闭客户端
        wg.Done()
    }()
    if err := op.Wait(context.TODO()); err != nil {
        // 处理等待过程中的错误
        return
    }
    // 镜像创建完成后的操作
}

func TakeImage(ctx context.Context, req *computepb.InsertImageRequest, wg *sync.WaitGroup) {
    c, err := compute.NewImagesRESTClient(ctx)
    if err != nil {
        // 处理客户端创建错误
        return
    }
    op, err := c.Insert(ctx, req)
    if err != nil {
        c.Close() // 创建操作失败,及时关闭客户端
        // 处理插入错误
        return
    }
    wg.Add(1)
    go WaitForImages(op, c, wg)
}

func Main() {
    images := []string{/* 镜像列表 */}
    var wg sync.WaitGroup
    ctx := context.TODO()
    for _, img := range images {
        img := img
        req := &computepb.InsertImageRequest{
            Project: myProject,
            ImageResource: &computepb.Image{
                Name:       &img,
                SourceDisk: &img,
            },
        }
        TakeImage(ctx, req, &wg)
    }
    wg.Wait()
}

修改说明

  • 将ImagesClient传递到协程中,在op.Wait执行完成后再关闭,确保等待过程中客户端始终有效
  • 处理创建操作失败的场景,及时关闭客户端避免资源泄漏
  • 给op.Wait添加错误处理,避免忽略潜在异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 16:01:14