[GODRIVER-1672] the diff of context.WithTimeout() and options.Clientoptions.ConnectTimeout Created: 06/Jul/20  Updated: 20/Dec/20  Resolved: 24/Jul/20

Status: Closed
Project: Go Driver
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Task Priority: Major - P3
Reporter: du liu Assignee: Kriti Ravindran (Inactive)
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

mongo-go-driver v1.3.4



 Description   

I set the ConnectTimeout, but it looks like no working.

This is my code:

 

 
type Conf struct {
      Host           string
      Port           string
      DbName         string
      ConnectTimeout time.Duration
      SocketTimeout  time.Duration
      MaxPoolSize    uint64
      MinPoolSize    uint64
      Direct         bool
  }
 
func Init() {
    opts := conf2options(e.Conf)
    c, err := mongo.Connect(NewCtx(e.Conf.ConnectTimeout),   
        opts.ApplyURI(fmt.Sprintf("mongodb://%s:%s/%s", e.Conf.Host,    e.Conf.Port, e.Conf.DbName)))
    if err != nil {
        return err 
    }   
  
    err = c.Ping(context.Background(), readpref.Primary())
    if err != nil {
        return err 
    }
}
func conf2options(conf *Conf) *options.ClientOptions {
      return &options.ClientOptions{
          ConnectTimeout: &conf.ConnectTimeout,
          SocketTimeout:  &conf.SocketTimeout,
          MaxPoolSize:    &conf.MaxPoolSize,
          MinPoolSize:    &conf.MinPoolSize,
          Direct:         &conf.Direct,
      }   
  }

I set `ConnectTimeout = 10 * time.second`, but the test output:

--- FAIL: TestClient (30.00s)
    engine_test.go:9: server selection error: server selection timeout, current topology: { Type: Single, Servers: [{ Addr: 127.0.0.1:27017, Type: Unknown, State: Connected, Average RTT: 0, Last error: connection() : dial tcp 127.0.0.1:27017: connect: connection refused }, ] }
FAIL
exit status 1
FAIL	go.study.org/mongoDemo/mongoorg	30.005s

It took 30 seconds, seems like default ConnectTimeout.

Then i use context.WithTimeout, it works.

func Init() {
    opts := conf2options(e.Conf) 
    c, err := mongo.Connect(NewCtx(e.Conf.ConnectTimeout), 
        opts.ApplyURI(fmt.Sprintf("mongodb://%s:%s/%s", e.Conf.Host,         e.Conf.Port, e.Conf.DbName)))
    if err != nil { 
        return err 
    }
    
    ctx, _ := context.WithTimeout(context.Backgroud(), 10*time.Second)
    err = c.Ping(ctx, readpref.Primary()) 
    if err != nil { 
        return err 
    }
}

the output:

--- FAIL: TestClient (10.00s)
    engine_test.go:9: context deadline exceeded
FAIL
exit status 1
FAIL	go.study.org/mongoDemo/mongoorg	10.006s

I think I used it(options.ClientOptions.ConnectTimeout) in the wrong way.But I can't found the true way.

Are there any way to make it works without context when used options.ClientOptions.ConnectTimeout?

 



 Comments   
Comment by du liu [ 20/Dec/20 ]

Thank you! ServerSelectionTimeout worked.

Comment by Kriti Ravindran (Inactive) [ 15/Jul/20 ]

During Server Selection, there is a default ServerSelectionTimeout that is set at 30s. This is the error that you are seeing instead of the Context timeout which you set for more than 30s. The Go Driver has various timeouts for parts of the stack, and will use the minimum between those timeouts and the context timeout that you pass.

ConnectTimeout should only be set past the default if network latency is very high and a connection could take longer than 30s. Your last error is connection refused, not a connection timeout, so it doesn’t seem like it has anything to do with your issue.

In order to set a context timeout for more than 30 seconds, you will need to set the ServerSelectionTimeout greater than your context timeout. This can be done through ClientOptions.SetServerSelection(time.Duration)(https://godoc.org/go.mongodb.org/mongo-driver/mongo/options#ClientOptions.SetServerSelectionTimeout).

Setting ServerSelectionTimeout to >30s probably won't help in your case. It's not a setting most users should change as the default should be more than enough for the driver to discover the cluster and execute operations. Looking at the error output, the LastError field is dial tcp: connection refused. This is from a net.Dialer.DialContext call and it's failing fast because the server refused the initial connection, which usually means the address is wrong. Can you try reproducing in a standalone Go program by running:

conn, err := net.Dial("tcp", "127.0.0.1:27018")
if err != nil {
   panic(err)
}

If this also reports connection refused, your server is either not accepting connections or the address is incorrect.

Comment by du liu [ 15/Jul/20 ]

 

func TestNewEngine(t *testing.T) {
     c, err := mongo.Connect(NewCtx(40*time.Second),
         options.Client().ApplyURI(fmt.Sprintf("mongodb://%s:%s/%s", "127.0.0.1", "27018", "test")).SetConnectTimeout(time.Second*10))
     if err != nil {
        t.Errorf("connect error: %+v", err)
     }
 
    if err := c.Ping(NewCtx(40*time.Second), readpref.Primary()); err != nil {
         t.Errorf("ping error: %+v", err)
    }
}

 output:

--- FAIL: TestNewEngine (30.00s) 
engine_test.go:21: ping error: server selection error: server selection timeout, current topology: { Type: Unknown, Servers: [{ Addr: 127.0.0.1:27018, Type: Unknown, State: Connected, Average RTT: 0, Last error: connection() : dial tcp 127.0.0.1:27018: connect: connection refused }, ] }

it can't change the default connect timeout.If i want the connect timeout > 30s, what would i do?

In this case, although I set a timeout,it's also 30s.

Comment by Kriti Ravindran (Inactive) [ 13/Jul/20 ]

The documentation for ClientOptions (https://godoc.org/go.mongodb.org/mongo-driver/mongo/options#ClientOptions) states that ConnectTimeout specifies a timeout that is used for creating connections to the server. ClientOptions based timeouts are used to timeout a specific section of a query. ConnectTimeout specifically controls how long the driver waits to fail a new connection. Passing Context.WithTimeout tells a blocking function that it should abandon its work (in this case, an entire query) after the timeout elapses (in your case, this will happen within client.Ping during server selection).

There is currently not a way to timeout an entire operation using ClientOptions-based timeouts. The only way to produce the timeout you are looking for is to use Context.withTimeout.

Generated at Thu Feb 08 08:36:53 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.