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

Hang in logout in panic

Open Crapulax opened this issue 7 years ago • 7 comments

When there is a panic while processing inbox messages the defer logout is hanging process. (and prevents seeing the stack trace).

Context:

  • listen update in a go routine
  • use IdleWithFallback in a go routine
  • messages processing in main routine (panic here hangs)

Workaround do not logout in panic case: defer func() { //prevents logout while panic, it hangs the process and prevents seeing failure stack if r := recover(); r != nil { fmt.Println("Recovered in f", r) panic(r) } else { c.Logout() } }()

Crapulax avatar Feb 06 '18 08:02 Crapulax

@Crapulax Did anything come of this?

daved avatar Mar 30 '18 08:03 daved

Sorry, but I do not understand your question. What do you mean?

Crapulax avatar Mar 30 '18 08:03 Crapulax

If you ask, if I had a feedback, answer is no. Now, I am using above mentioned solution and it works just fine, I can catch the underlying error. At the end of the day, my issue was not so much with the freeze but with the inability to see the triggering panic stack. But I guess that yes it should be handled in the library. There is so many channels involved in it that it is easy to run into deadlocks and by the way not suspect an issue, at first glance, within your code.

Crapulax avatar Mar 30 '18 08:03 Crapulax

Thank you for sharing your experience.

daved avatar Mar 30 '18 15:03 daved

I'm not sure what should be done here. What happens if you replace defer c.Logout() with defer c.Terminate()?

emersion avatar Apr 07 '18 20:04 emersion

package main

import (
	"fmt"
	"github.com/emersion/go-imap/client"
)

func main() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("PANIC", err)
		}
	}()
	// Connect to server
	c, err := client.DialTLS("mail.example.org:993", nil)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("Connected")

	// Don't forget to logout
	defer c.Logout()

	// Login
	if err := c.Login("username", "password"); err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("Logged in")

	// panic
	panic("PANIC will be catch by Logout!!!")
}

beiping96 avatar Apr 15 '19 09:04 beiping96

For fix this:

defer func() {
	//prevents logout while panic, it hangs the process and prevents seeing failure stack
	if r := recover(); r != nil {
		fmt.Println("Recovered in f", r)
		panic(r)
	} else {
		c.Logout()
	}
}()
defer func () {
	go c.Logout()
}()

beiping96 avatar Apr 15 '19 09:04 beiping96