{"record":{"id":"c3c8fe1cd91824d8","repo":"geektutu/7days-golang","slug":"rpc-client-connect-timeout-expect-within-s","errorCode":null,"errorMessage":"rpc client: connect timeout: expect within %s","messagePattern":"rpc client: connect timeout: expect within (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-rpc/day4-timeout/client.go","lineNumber":269,"sourceCode":"\t}\n\t// close the connection if client is nil\n\tdefer func() {\n\t\tif err != nil {\n\t\t\t_ = conn.Close()\n\t\t}\n\t}()\n\tch := make(chan clientResult)\n\tgo func() {\n\t\tclient, err := f(conn, opt)\n\t\tch <- clientResult{client: client, err: err}\n\t}()\n\tif opt.ConnectTimeout == 0 {\n\t\tresult := <-ch\n\t\treturn result.client, result.err\n\t}\n\tselect {\n\tcase <-time.After(opt.ConnectTimeout):\n\t\treturn nil, fmt.Errorf(\"rpc client: connect timeout: expect within %s\", opt.ConnectTimeout)\n\tcase result := <-ch:\n\t\treturn result.client, result.err\n\t}\n}\n\n// Dial connects to an RPC server at the specified network address\nfunc Dial(network, address string, opts ...*Option) (*Client, error) {\n\treturn dialTimeout(NewClient, network, address, opts...)\n}\n","sourceCodeStart":251,"sourceCodeEnd":279,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-rpc/day4-timeout/client.go#L251-L279","documentation":"dialTimeout in gee-rpc/day4-timeout enforces opt.ConnectTimeout on the asynchronous dial handshake. If the connection is not established (and options not exchanged) within that window, it returns \"rpc client: connect timeout: expect within %s\" and abandons the attempt even though the goroutine may still complete later.","triggerScenarios":"Dial with an Option whose ConnectTimeout > 0 while net.Dial plus NewClient (option exchange) exceed the deadline — slow/unreachable host, DNS stall, firewalled port, or a ConnectTimeout set shorter than network RTT.","commonSituations":"Server not listening (port closed, firewall silently dropping); wrong address in tests/CI without the server up; ConnectTimeout of a few milliseconds in a latency-sensitive environment; server accepting TCP but never responding to the options header.","solutions":["Increase opt.ConnectTimeout to comfortably exceed worst-case connect + options-exchange time","Verify the server is running and reachable at the address (telnet/nc the port)","Leave ConnectTimeout as 0 to disable the deadline and use the OS connect timeout","Check for silent firewall drops between client and server"],"exampleFix":"// before\nopt := &geerpc.Option{ConnectTimeout: 10 * time.Millisecond}\nclient, err := geerpc.Dial(\"tcp\", \"remote:9000\", opt)\n// after\nopt := &geerpc.Option{ConnectTimeout: 3 * time.Second}\nclient, err := geerpc.Dial(\"tcp\", \"remote:9000\", opt)","handlingStrategy":"retry","validationCode":"if opt.ConnectTimeout != 0 && opt.ConnectTimeout < 500*time.Millisecond {\n\treturn errors.New(\"ConnectTimeout too small; use >= 500ms or 0 to disable\")\n}","typeGuard":null,"tryCatchPattern":"client, err := geerpc.Dial(\"tcp\", addr, opt)\nif err != nil && strings.Contains(err.Error(), \"connect timeout\") {\n\ttime.Sleep(500 * time.Millisecond)\n\tclient, err = geerpc.Dial(\"tcp\", addr, opt) // bounded retry\n}","preventionTips":["Budget ConnectTimeout for DNS + TCP connect + the JSON options exchange","Probe the server port before dialing in deployment scripts","Use 0 (disabled) when connecting over slow or lossy networks","Add bounded retries with backoff around Dial"],"tags":["rpc","network","timeout","dial"],"backgroundTag":"connect-timeout","analyzedSha":"cf3644382101dc13e7fd92e8f5c66cabc51bcd3b","analyzedAt":"2026-09-03T18:31:24.087Z","contentChangedAt":"2026-09-03T18:31:24.087Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}