Ask /r/golang: How do you handle db/cache connections and errors in a web project?

xuanbao · · 617 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>While this is not directly related to Golang, I still have this problem while coding in Go. I write a nice API for a fairly large enough web project. It is mostly CRUD. Most of the handlers look line foloowing:</p> <pre><code>func handler(w http.ResponseWriter, req *http.Request) { db, err := GetDB() if err != nil { w.write(&#34;500&#34;) } results, err != db.query(&#34;seleect something from something else where somethinsg = ?&#34;, req.param(&#34;id&#34;) if err != nil { w.write(&#34;500&#34;) } w.write(jsonResults) } </code></pre> <p>My problem is, I repeat most of the code here, should I use GetDB() as a singleton function? But singletons and global variables are said to be bad. Anyways, should my signleton return error or panic? Should I recover and send 500 on any error? Some enterprise frameworks like Spring allows you to write services and handles their lifetime. Should I try to find something similar to it? </p> <p>I do not want to repeat code, and I do not want to write buggy software (as a normal person) but is using singletons bad? What is your workflow for CRUD applications? </p> <hr/>**评论:**<br/><br/>RickAndMorty_forever: <pre><p>It took me about a solid week of dogged reading to really get a grasp on Go and I&#39;m still a beginner. Here&#39;s a few things I picked up...</p> <ul> <li><p>The language really promotes unit tests. My handlers use an interface to interact with the database</p></li> <li><p>you&#39;ll find most db drivers handle connection pooling for you</p></li> <li><p>Using panic as exception handling is an anti-pattern. Errors are values and often have valuable data. Logging them and returning an appropriate error message is usually going to be the correct course of action. Panicking is for when something really bad happens </p></li> </ul></pre>robertmeta: <pre><blockquote> <p>should I use GetDB() as a singleton function?</p> </blockquote> <p>Are you using an SQL driver under that GetDB -- if so, it already handles that. <a href="https://golang.org/pkg/database/sql/">https://golang.org/pkg/database/sql/</a> &#34;DB is a database handle representing a pool of zero or more underlying connections. It&#39;s safe for concurrent use by multiple goroutines. The sql package creates and frees connections automatically; it also maintains a free pool of idle connections.&#34; (Always read the docs)</p> <blockquote> <p>But singletons and global variables are said to be bad.</p> </blockquote> <p>Don&#39;t worry about &#34;said to be bad&#34; and worry about WHY things are said to be bad. If those reasons don&#39;t apply to you then don&#39;t worry. Globals often muck up testing and can be confusing, but if that doesn&#39;t apply to you -- don&#39;t worry about it.</p> <blockquote> <p>Anyways, should my signleton return error or panic? </p> </blockquote> <p>Umm, panics are for exceptional cases, your DB being unavailable is not that. </p> <blockquote> <p>Should I recover and send 500 on any error?</p> </blockquote> <p>Umm, panics should be things that &#34;never happen&#34; -- don&#39;t use them as control flow.</p> <blockquote> <p>Some enterprise frameworks like Spring allows you to write services and handles their lifetime. Should I try to find something similar to it?</p> </blockquote> <p>huh?</p> <p>P.S. gofmt</p></pre>mustafaakin: <pre><p>But isn&#39;t not being able to query database exceptional case? I mean, it is a very common flow, could not connect to database, fail and send HTTP 50x - Server error to client. </p> <p>By (Java) Spring&#39;s services, I meant dependency injection. Not that I like it, but you define your service as a class, and whenever you use it, you just define it and write an annotation to top @Autowired and it instantiates it for your object. I found something similar: <a href="http://blog.parse.com/learn/engineering/dependency-injection-with-go/" rel="nofollow">http://blog.parse.com/learn/engineering/dependency-injection-with-go/</a></p></pre>Grundlebuttskin: <pre><p>If you can&#39;t satisfy the request, respond with 503 temporarily unavailable. You can suggest a retry-after with a header too, in the case of planned downtime.</p></pre>robertmeta: <pre><p>That is great advice. </p></pre>robertmeta: <pre><blockquote> <p>But isn&#39;t not being able to query database exceptional case?</p> </blockquote> <p>No, it is a very common error. Can happen from overloaded DB, upgrade of DB (will be down for a few MS in lots of cases), etc. </p> <blockquote> <p>I mean, it is a very common flow, could not connect to database, fail and send HTTP 50x - Server error to client.</p> </blockquote> <p>Sure, do that with errors, not exceptions. </p> <blockquote> <p>I meant dependency injection</p> </blockquote> <p>DI is fine, lots of people pass in database handles. </p></pre>nerdwaller: <pre><p>I usually make a data access interface and make a database implementation of it and pass that into a struct that defines my endpoints that require that resource. E.g. <a href="https://play.golang.org/p/JyZ2BE41pe" rel="nofollow">https://play.golang.org/p/JyZ2BE41pe</a></p> <p>Makes for much simpler unit testing since you can easily mock the interface for getting users (or whatever the subject may be).</p> <p>edit: fixed link with db impl</p></pre>quiI: <pre><p>You may find it helpful to add some structure to your code and separate the concerns. You are struggling because your <em>http</em> handler is also worrying about database access.</p> <p>I&#39;ve made an example about how you could structure your code.</p> <p><a href="https://play.golang.org/p/W_JrRf4z4A" rel="nofollow">https://play.golang.org/p/W_JrRf4z4A</a></p></pre>barsonme: <pre><p>Don&#39;t panic. </p> <p>panic is for conditions that should <em>never</em> happen or prevent the app from functioning (e.g., it can&#39;t find the config files on startup—and even then I&#39;d recommend the log package.)</p> <p>If a DB query returns an error first check what it is. If it&#39;s an error with your DB, return status 500. If it&#39;s an error because the user submitted a bad request, return that to the user.</p> <p>Also, make sure to log <em>all</em> errors that aren&#39;t due to bad requests from users. </p></pre>

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

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