Prevent go app exiting on panic

agolangf · · 486 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I get that Go really really really really doesn&#39;t want you to use panics unless something truly is horribly horribly wrong. However, in the case of a web app, if something does panic, then my whole app exits and bam, no more web server. This freaks me the hell out. Is there any way to prevent this behavior within the app (other than the obvious- don&#39;t do things that panic) or do I need to create some sort of second &#34;monitor&#34; app that restarts the web server if it dies?</p> <hr/>**评论:**<br/><br/>TheMerovius: <pre><p>The same arguments that apply to a cli or whatever, also apply to a web-app: If it panics, that means it has a bug and pretty much all distributed computing out there assumes, for correctness, that nodes stop if they have such a failure. So, you <em>should</em> crash on panic.</p> <p>That being said: If you do <em>really</em> want to do that, you&#39;d need to wrap every go statement in a function, which calls <code>defer func() { recover() }</code> and then continues with the argument to go. You&#39;re unlikely to be able to actually do that, because you depend on other people&#39;s go-code and they might use goroutines themselves, but it&#39;s the only way.</p> <p>So yes. The correct way, to deal with this, is to make your infrastructure resiliant against such sudden failures. For a simple webapp, using systemd or something to restart on failures might be sufficient. Doing it reliably for larger stuff is why companies spend big money on teams that take care of it. Because it&#39;s not easy.</p></pre>Fuzzerker: <pre><p>hmm, thats what I thought. as you said, the issue really comes in using 3rd party libraries that may or may not recover from all goroutines. it makes sense to solve this at the infrastructure level but I was hoping for a bit more internal safety ( a la node or .Net)</p></pre>TheMerovius: <pre><p>When your software is buggy, it isn&#39;t safe. A panic means, that your software is broken and exiting <em>is</em> the safe thing.</p></pre>Matir: <pre><p>Where, exactly, would you expect execution to continue?</p></pre>JHunz: <pre><p>My company&#39;s solution is to wrap everything in calls that will log and recover from panics without crashing the app:</p> <pre><code>func CallWithPanicProtection(f func(), prefix string, shouldTerminate bool) { defer func() { const howFarBack int = 10 if recovered := recover(); recovered != nil { l4g.Info(&#34;CallWithPanicProtection panic recovery: %s\r\n&#34;, recovered) message := fmt.Sprintf(&#34;Run-time panic in %s: %v&#34;, prefix, recovered) LogStack(howFarBack, LOG_LEVEL_CRITICAL, message) // Log this report with Sentry reports.ReportsInterface.CapturePanic(message, recovered, nil) if shouldTerminate { // Give the log4go log time to flush time.Sleep(time.Second * 3) // Re-panic if this is a high-level enough problem panic(recovered) } } }() f() } </code></pre></pre>bkeroack: <pre><p>That&#39;s horrible. </p></pre>knotdjb: <pre><blockquote> <p>wrap everything</p> </blockquote> <p>That&#39;s overkill. Identify which functions can potentially panic and wrap (or defer recover) those.</p></pre>JHunz: <pre><p>There are panics in the go standard library</p></pre>knotdjb: <pre><p>Sure but are you really going to wrap something innocuous as strconv.Itoa or strings.ToUpper? </p></pre>JHunz: <pre><p>Well, no, good grief. When I said we wrap everything, I meant we wrap main and the top-level function in any new goroutine. Everything is wrapped, but we don&#39;t do it for every single call.</p></pre>natefinch: <pre><p>In my experience, panics are actually quite rare in Go code. Certainly in my experience, they happen WAY less often than unhandled exceptions in C# (comparing two ~500k LOC projects I&#39;ve worked on).</p> <p>However, that being said, every web app <em>should</em> run as a service with the OS&#39;s service runner (Windows Services or systemd/upstart on linux or whatever OSX uses), which can be configured to rerun your application.</p></pre>itsmontoya: <pre><p>You really shouldn&#39;t be experiencing panics. If you are, you should look into your coding style and ensure you are following best practices.</p></pre>Fwippy: <pre><p>Just configure your init system to restart the service if it exists. This is a solved problem, don&#39;t reinvent the wheel.</p></pre>emersion_fr: <pre><p>If you really need it, you can use <a href="https://github.com/bugsnag/panicwrap" rel="nofollow">https://github.com/bugsnag/panicwrap</a></p></pre>kpurdon: <pre><p>In the case of a web app / http api you want to return an error to your user (but let them continue to interact) and log the information for your debugging. I use <a href="https://github.com/kpurdon/http/blob/master/recovery/main.go" rel="nofollow">this</a> middleware to do that for my go apis.</p></pre>tscs37: <pre><p>You can either use a monitor app or you use a defer.</p> <p>A monitor app has obviously the crux that it could crash, so who monitors the monitor?</p> <p>A defer is probably the more reliable solution. From there you have two options again;</p> <ol> <li><p>actually execute inside a function and use the defer to tell main() that you want to restart via modifying return codes</p></li> <li><p>use the defer to re-exec the service, effectively doing a full restart (which is the best option IMO)</p></li> </ol></pre>alexaandru: <pre><p>This is the backbone of what I use: <a href="https://gist.github.com/alexaandru/eb13b0608eb5d6d34d2d" rel="nofollow">https://gist.github.com/alexaandru/eb13b0608eb5d6d34d2d</a> what you care about is <a href="https://gist.github.com/alexaandru/eb13b0608eb5d6d34d2d#file-handlers-go-L52-L63" rel="nofollow">https://gist.github.com/alexaandru/eb13b0608eb5d6d34d2d#file-handlers-go-L52-L63</a></p> <p>Cheers!</p></pre>SingularityNow: <pre><p>You should be able to wrap your request handler s in middleware that can recover from a panic and log (or otherwise handle) it. That way your whole server doesn&#39;t crash, you get information on the crash, and don&#39;t have to litter you code with recovery concerns.</p></pre>patrickdappollonio: <pre><p>You need to &#34;recover&#34; from panic: <a href="https://www.dotnetperls.com/recover-go" rel="nofollow">https://www.dotnetperls.com/recover-go</a></p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

486 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传