Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect panic(nil) and normal execution in deferred function Go?

Tags:

go

panic

The go runtime can detect panic(nil) and reports an error.

However, I can't detect panic(nil) with recover() in a deferred function because it returns nil, so I cannot differentiate it from normal execution (no panic) as I would test for the return value of recover() to be nil.

For example,

defer func(){
    var err = recover()
    if err != nil {
       // Real serious situation. Panic from inner code.
       // And we may have some critical resources which 
       // must be cleaned-up at any cases.
       // However, this will not be executed for panic(nil) 

       rollback()

       // I am still not sure that how should I treat `panic`…
       // Should I just ignore them?
    }
}()

var err = doTransaction()
if err == nil {
    commit()    // Happy case.
} else {
    rollback()  // Regular execution. Just a lucky case.
}

ROLLBACK is just an example, and I think I can have plenty of critical cases needs cleanup. Well, those cleanup code won't be executed on real program crash too, but I want to defend as much as possible.

How can I detect any panic regardless of its parameter in a deferred function?

like image 827
eonil Avatar asked Oct 29 '13 15:10

eonil


1 Answers

I simply can set a flag before exit.

AFAIK, panic is goroutine-specific, and single goroutine is guaranteed to be in single thread. So synchronization/locking is not required around variable ok. If I'm wrong, please correct me.

func clean(ok *bool) {
    if *ok {
        log.Printf("Execution OK. No panic detected.\n")
    } else {
        var reason = recover()
        log.Printf("Some bad thing happen. reason = %v\n", reason)
        panic("Abnormal exit. Program abandoned. Stack-trace here.")
        debug.PrintStack() // Oops. this will not run.
    }
}

func main() {
    var ok bool = false

    defer clean(&ok)
    panic(nil)

    test1() // Here's the main job.

    ok = true
    log.Printf("All work done. Quit gracefully.\n")
}
like image 112
eonil Avatar answered Oct 15 '22 09:10

eonil