Docker容器中的服务器连接被拒绝,我应该在测试中添加time.Sleep(100*time.millis秒)吗?
我目前正在一个服务器上工作,该服务器设计为在Docker容器中运行 以下是我的测试设置方法:Docker容器中的服务器连接被拒绝,我应该在测试中添加time.Sleep(100*time.millis秒)吗?,docker,http,go,Docker,Http,Go,我目前正在一个服务器上工作,该服务器设计为在Docker容器中运行 以下是我的测试设置方法: func TestMain(m *testing.M) { schedulerName := "scheduler1" IP, err := container.StartNewScheduler(schedulerName) if err != nil { log.Println("Could not create containe
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.startNewsScheduler(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调用,在调用它之前设置了一个计时器
func post(url string, contentType string, body io.Reader, t *testing.T) *http.Response {
t.Helper()
response, err := http.Post(url, contentType, body)
if err != nil {
//There is an error where the container takes a second to boot up and so
//the scheduler isn't running when the first request is sent, so we try
//one more time here and check again.
time.Sleep(100 * time.Millisecond) <--- Right here
response, err = http.Post(url, contentType, body)
if err != nil {
t.Fatal(err)
}
}
return response
}
func post(url字符串、contentType字符串、body io.Reader、t*testing.t)*http.Response{
t、 助手()
响应,错误:=http.Post(url、contentType、正文)
如果错误!=零{
//有一个错误,容器需要一秒钟才能启动,因此
//发送第一个请求时,调度程序未运行,因此我们尝试
//再来一次,再检查一遍。
time.Sleep(100*time.millis秒)您可以在容器内运行测试代码,通过docker compose启动,并带有选项。好的,在我进一步考虑修改源代码后,请告诉我您是否认为这是解决我问题的好方法。我仍在学习Go和HTTP服务器,因此任何输入都非常感谢
以下是我的解决方案/想法:
以前,一旦创建了容器,我就返回了它的IP地址,并且忘记了它
现在,我创建了一个go例程,该例程反复尝试向服务器发送POST请求。如果没有失败,则通过一个通道发送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)
IP:=info.NetworkSettings.Networks[networkName].IPAddress
作品:=制作(陈波)
ctx,canelRoutine:=context.WithCancel(context.Background())
延迟canelRoutine()
go func(ctx context.context){
requestBody,\:=json.Marshal(map[string]string{
“代码”:“print()”,
})
挑选{
案例这些测试的目的是确保服务器在docker容器内工作。我已经有其他测试在容器外测试服务器,所以我认为这不会起作用。取决于:
无法解决此问题。(它确保目标容器存在,DNS解析将成功,但不确保目标容器中的进程正在运行。)尽管这看起来有很多代码,但这是一种很好的方法:容器在响应HTTP请求时实际上正在运行,而不是之前。您可以在尝试调用容器的For
循环中设置延迟,并且您可能应该将select
语句放在For
循环中(因此,当上下文被取消时,您将停止ping容器)。@DavidMaze感谢您的响应。我已经在for循环外有select语句了。我应该删除该语句并将其放在for循环内,还是两者都做?
timer := time.After(500 * time.Millisecond)
select {
case <-works:
return IP, nil
case <-timer:
return IP, &UnreachableContainerError{name: schedulerName}
}
//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}
}
}