亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Docker 容器連接中的服務器被拒絕,我應該在測試中添加 time.Sleep

Docker 容器連接中的服務器被拒絕,我應該在測試中添加 time.Sleep

Go
慕姐8265434 2022-06-27 17:19:49
我目前正在開發一個設計為在 Docker 容器中運行的服務器。這是我的測試設置方法:func TestMain(m *testing.M) {    schedulerName := "scheduler1"    IP, err := container.StartNewScheduler(schedulerName)    if err != nil {        log.Println("Could not create container.")        log.Fatal(err)    }    serverIP = IP    code := m.Run()    cleanupContainer(schedulerName)    os.Exit(code)}該行container.StartNewScheduler(schedulername)啟動了一個名為“scheduler1”的新 docker 容器,并告訴它在其中運行服務器。接下來我使用在后臺運行的容器運行我的測試,現在我只有一個測試。func TestNewScheduler(t *testing.T) {    testCodeInput := "THIS IS A TEST"    requestBody, err := json.Marshal(map[string]string{        "Code": fmt.Sprintf("print(\"%s\")", testCodeInput),    })    if err != nil {        t.Fatal(err)    }    url := fmt.Sprintf("http://%s:%d/execute/python", serverIP, 3000)    contentType := "application/json"    body := bytes.NewBuffer(requestBody)    response := post(url, contentType, body, t)    actual := parseOutput(response.Body, t)    response.Body.Close()    expected := fmt.Sprintf("{\"Stdout\":\"%s\\n\"}", testCodeInput)    if actual != expected {        t.Fatalf("Expected %s, but got %s", expected, actual)    }}我遇到的問題是有時我的連接被拒絕,有時我沒有。server_container_test.go:51: Post http://172.20.0.2:3000/execute/python: dial tcp 172.20.0.2:3000: connect: connection refused我注意到,每當我嘗試調試問題時,一切似乎都運行良好。我的運行理論是因為當我單步執行代碼時,容器有更多時間啟動并讓服務器在其中運行。為了測試我的假設,我在我的 post 方法中添加了第二個 post 調用,并在調用它之前設置了一個計時器。還有其他人對可能導致我這個問題的原因有任何猜測嗎?如果我的假設是正確的,這是解決此問題的最佳方法嗎?在測試中添加 time.Sleep 是不是一個壞主意?
查看完整描述

2 回答

?
海綿寶寶撒

TA貢獻1809條經驗 獲得超8個贊

好的,經過更多思考后,我更改了源代碼,如果您認為這是解決我的問題的好方法,請告訴我。我仍在學習 Go 和 HTTP 服務器,因此感謝任何輸入。


這是我的修復/想法:


以前創建容器后,我只是返回了它的 IP 地址并忘記了它。


現在我創建了一個重復嘗試向服務器發送 POST 請求的 go 例程。如果它沒有失敗,那么我通過通道發送 true 并關閉函數。


    IP := info.NetworkSettings.Networks[networkName].IPAddress

    works := make(chan bool)

    ctx, canelRoutine := context.WithCancel(context.Background())

    defer canelRoutine()


    go func(ctx context.Context) {

        requestBody, _ := json.Marshal(map[string]string{

            "Code": "print()",

        })

        select {

        case <-ctx.Done():

            return

        default:

            for {

                _, err := http.Post(

                    fmt.Sprintf("http://%s:%d/execute/python", IP, 3000),

                    "application/json",

                    bytes.NewBuffer(requestBody),

                )

                if err == nil {

                    works <- true

                    return

                }

            }

        }

    }(ctx)


發送 goroutine 后,我創建了一個計時器并等待計時器返回或 goroutine。


    timer := time.After(500 * time.Millisecond)

    select {

    case <-works:

        return IP, nil

    case <-timer:

        return IP, &UnreachableContainerError{name: schedulerName}

    }

這個解決方案的好處是我現在引入了一個 UnreachableContainerError ,它允許我更具體地了解我的錯誤消息,并且可以在接收端進行檢查。我還會以任何一種方式發回 IP 地址,以防客戶端出于其他原因需要它。


如果您想查看它,這是完整的 StartNewScheduler 方法。


//StartNewScheduler starts a new scheduler with the given options.

//returns the IP address for the given scheduler.

func StartNewScheduler(schedulerName string) (string, error) {

    ///Defaults

    dockerfile := "Dockerfile_standard"

    networkName := "scheduler-cluster"

    imageID := "lkelly93/scheduler_image:latest"


    cli, err := client.NewEnvClient()

    if err != nil {

        return "", err

    }


    err = createDefaultImageIfNeeded(

        cli,

        imageID,

        dockerfile)


    if err != nil {

        return "", err

    }


    err = createSchedulerClusterNetworkIfNeeded(cli, networkName)

    if err != nil {

        return "", err

    }


    ctx := context.Background()

    resp, err := cli.ContainerCreate(

        ctx,

        &container.Config{Image: imageID},

        &container.HostConfig{

            NetworkMode: container.NetworkMode(networkName),

            Privileged:  true,

        },

        nil,

        schedulerName,

    )


    if err != nil {

        return "", err

    }


    err = cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{})

    if err != nil {

        return "", err

    }


    //Get container IP

    info, err := cli.ContainerInspect(ctx, resp.ID)

    if err != nil {

        return "", err

    }


    IP := info.NetworkSettings.Networks[networkName].IPAddress

    works := make(chan bool)

    ctx, canelRoutine := context.WithCancel(context.Background())

    defer canelRoutine()


    go func(ctx context.Context) {

        requestBody, _ := json.Marshal(map[string]string{

            "Code": "print()",

        })

        select {

        case <-ctx.Done():

            return

        default:

            for {

                _, err := http.Post(

                    fmt.Sprintf("http://%s:%d/execute/python", IP, 3000),

                    "application/json",

                    bytes.NewBuffer(requestBody),

                )

                if err == nil {

                    works <- true

                    return

                }

            }

        }

    }(ctx)


    timer := time.After(500 * time.Millisecond)

    select {

    case <-works:

        return IP, nil

    case <-timer:

        return IP, &UnreachableContainerError{name: schedulerName}

    }

}


查看完整回答
反對 回復 2022-06-27
?
嗶嗶one

TA貢獻1854條經驗 獲得超8個贊

您可以在容器內運行測試代碼,通過 docker compose 使用選項depends_on 啟動。



查看完整回答
反對 回復 2022-06-27
  • 2 回答
  • 0 關注
  • 162 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號