go-imap icon indicating copy to clipboard operation
go-imap copied to clipboard

`UidFetch` never return

Open beiping96 opened this issue 5 years ago • 1 comments

I try to build an IMAP email client, and it has many email accounts.

When I use the pprof for debugging my codes, I found in some cases, the UidFetch function never return.

I'm pretty sure the follwing: 1. I had set the net.Conn deadline (half of hour); 2. The message channel used in UidFetch has the big size (999), and SeqSet has just one number.

Here are the two goroutines that blocked.

goroutine 27794 [select, 75 minutes]:
github.com/emersion/go-imap/client.(*Client).execute(0xc00485a000, 0xc6b560, 0xc005d06d90, 0xc6b5e0, 0xc00000d648, 0x4, 0x28, 0x30)
	D:/Go/pkg/mod/github.com/emersion/[email protected]/client/client.go:261 +0x38e
github.com/emersion/go-imap/client.(*Client).fetch(0xc00485a000, 0x1, 0xc00aec9340, 0xc003ed8690, 0x3, 0x3, 0xc0001bae40, 0x0, 0x0)
	D:/Go/pkg/mod/github.com/emersion/[email protected]/client/cmd_selected.go:153 +0x152
github.com/emersion/go-imap/client.(*Client).UidFetch(0xc00485a000, 0xc00aec9340, 0xc003ed8690, 0x3, 0x3, 0xc0001bae40, 0x1, 0x2)
	D:/Go/pkg/mod/github.com/emersion/[email protected]/client/cmd_selected.go:169 +0x65
// exec UidFetch
grabmail/grab/client.(*imap).FetchInboxMail(0xc00353e0f0, 0xc73f00, 0xc00038a000, 0xc000f7d1c0, 0x7, 0x7, 0x7, 0x7, 0x8, 0x0, ...)
	D:/Go/src/grabmail/grab/client/imap.go:151 +0x459
grabmail/grab.run(0xc73f00, 0xc00038a000, 0xb8ce75, 0x7, 0xc000497c80, 0x0, 0x0)
	D:/Go/src/grabmail/grab/grab.go:205 +0x6cf
grabmail/grab.(*Grab).acRun.func2(0xc00017d200, 0xc0000982a0, 0xc0000a8550, 0xc73f00, 0xc00038a000, 0xc000497c80)
	D:/Go/src/grabmail/grab/grab.go:153 +0x155
created by grabmail/grab.(*Grab).acRun
	D:/Go/src/grabmail/grab/grab.go:135 +0x38c

// guess this goroutine by `go reader()` after exec UidFetch
goroutine 27596 [IO wait, 75 minutes]:
internal/poll.runtime_pollWait(0x7f0a57e7ef60, 0x72, 0xc0074806c0)
	C:/Go/src/runtime/netpoll.go:173 +0x66
internal/poll.(*pollDesc).wait(0xc0004abd18, 0x72, 0xffffffffffffff00, 0xc6da80, 0x11454d8)
	C:/Go/src/internal/poll/fd_poll_runtime.go:85 +0x9a
internal/poll.(*pollDesc).waitRead(0xc0004abd18, 0xc002362000, 0x7f1b, 0x7f1b)
	C:/Go/src/internal/poll/fd_poll_runtime.go:90 +0x3d
internal/poll.(*FD).Read(0xc0004abd00, 0xc0023620e5, 0x7f1b, 0x7f1b, 0x0, 0x0, 0x0)
	C:/Go/src/internal/poll/fd_unix.go:169 +0x179
net.(*netFD).Read(0xc0004abd00, 0xc0023620e5, 0x7f1b, 0x7f1b, 0x408a3b, 0xc00001c000, 0xace9c0)
	C:/Go/src/net/fd_unix.go:202 +0x4f
net.(*conn).Read(0xc0038c8028, 0xc0023620e5, 0x7f1b, 0x7f1b, 0x0, 0x0, 0x0)
	C:/Go/src/net/net.go:177 +0x68
crypto/tls.(*block).readFromUntil(0xc006253ef0, 0xc6c780, 0xc0038c8028, 0x401d, 0xc0038c8028, 0x0)
	C:/Go/src/crypto/tls/conn.go:492 +0x89
crypto/tls.(*Conn).readRecord(0xc00006f180, 0xbcde17, 0xc00006f2a0, 0x0)
	C:/Go/src/crypto/tls/conn.go:638 +0x1f3
crypto/tls.(*Conn).Read(0xc00006f180, 0xc0086cc000, 0x1a520, 0x1a520, 0x0, 0x0, 0x0)
	C:/Go/src/crypto/tls/conn.go:1145 +0xf1
bufio.(*Reader).Read(0xc00066d440, 0xc0086cc000, 0x1a520, 0x1a520, 0x4000, 0x0, 0x0)
	C:/Go/src/bufio/bufio.go:202 +0x127
io.ReadAtLeast(0xc6b180, 0xc0018c0060, 0xc008680000, 0x66520, 0x66520, 0x66520, 0xa7fa80, 0x1, 0xc008680000)
	C:/Go/src/io/io.go:310 +0x88
io.ReadFull(0xc6b180, 0xc0018c0060, 0xc008680000, 0x66520, 0x66520, 0x66520, 0x0, 0xc001ada680)
	C:/Go/src/io/io.go:329 +0x58
github.com/emersion/go-imap.(*Reader).ReadLiteral(0xc0018c0060, 0x0, 0x0, 0x0, 0x0)
	D:/Go/pkg/mod/github.com/emersion/[email protected]/read.go:256 +0x257
github.com/emersion/go-imap.(*Reader).ReadFields(0xc0018c0060, 0x28, 0x1, 0x0, 0x0, 0x1)
	D:/Go/pkg/mod/github.com/emersion/[email protected]/read.go:314 +0x599
github.com/emersion/go-imap.(*Reader).ReadList(0xc0018c0060, 0x0, 0x0, 0x0, 0x0, 0xc0035f69a0)
	D:/Go/pkg/mod/github.com/emersion/[email protected]/read.go:364 +0x12c
github.com/emersion/go-imap.(*Reader).ReadFields(0xc0018c0060, 0xc007480e18, 0x9d9b58, 0xc007480e18, 0x40c3d8, 0x30)
	D:/Go/pkg/mod/github.com/emersion/[email protected]/read.go:318 +0x5d9
github.com/emersion/go-imap.(*Reader).ReadLine(0xc0018c0060, 0xc003cab2c0, 0x0, 0x0, 0x1, 0xc0035f6980)
	D:/Go/pkg/mod/github.com/emersion/[email protected]/read.go:380 +0x2f
github.com/emersion/go-imap.ReadResp(0xc0018c0060, 0x6, 0xc00051b3e0, 0x0, 0x0)
	D:/Go/pkg/mod/github.com/emersion/[email protected]/response.go:91 +0x162
github.com/emersion/go-imap/client.(*Client).readOnce(0xc00485a000, 0xbcda01, 0x0, 0x0)
	D:/Go/pkg/mod/github.com/emersion/[email protected]/client/client.go:145 +0x50
github.com/emersion/go-imap/client.(*Client).reader(0xc00485a000)
	D:/Go/pkg/mod/github.com/emersion/[email protected]/client/client.go:130 +0x5d
created by github.com/emersion/go-imap/client.(*Client).handleGreetAndStartReading
	D:/Go/pkg/mod/github.com/emersion/[email protected]/client/client.go:502 +0x16e
dialer := new(net.Dialer)
dialer.Timeout =  time.Duration(30) * time.Minute
cli, err := DialWithDialer(dialer, addr)


// DialWithDialer connects to an IMAP server using an unencrypted connection
// using dialer.Dial.
//
// Among other uses, this allows to apply a dial timeout.
func DialWithDialer(dialer *net.Dialer, address string) (c *Client, err error) {
	conn, err := dialer.Dial("tcp", address)
	if err != nil {
		return nil, err
	}

	// We don't return to the caller until we try to receive a greeting. As such,
	// there is no way to set the client's Timeout for that action. As a
	// workaround, if the dialer has a timeout set, use that for the connection's
	// deadline.
	if dialer.Timeout > 0 {
		err = conn.SetDeadline(time.Now().Add(dialer.Timeout))
		if err != nil {
			return
		}
	}

	c, err = New(conn)
	return
}

Any suggestion will be helpful. Tks.

beiping96 avatar May 24 '19 09:05 beiping96

I have got the same issue @beiping96 beiping96 Have you solved the issue?

spiritchais avatar Feb 02 '21 08:02 spiritchais

Closing because this is an issue about go-imap v1. I'm now focusing on go-imap v2.

Please re-open if you can reproduce with go-imap v2.

emersion avatar Apr 04 '23 14:04 emersion