commit 81e75f92710e82d040f699d1c86a7f2bfc7c745e
parent 8f2058dadcc24f999faaeeadec1fd5e40f278303
Author: David Eisinger <[email protected]>
Date: Tue, 20 Jun 2023 12:26:23 -0400
Add go link
Diffstat:
2 files changed, 232 insertions(+), 0 deletions(-)
diff --git a/content/notes/golang/index.md b/content/notes/golang/index.md
@@ -15,6 +15,10 @@ references:
url: https://medium.com/golang-learn/go-project-layout-e5213cdcfaa2
date: 2023-06-13T15:00:02Z
file: medium-com-efpmux.txt
+- title: "Gopher Wrangling. Effective error handling in Go | Stephen's Tech Blog"
+ url: https://stephenn.com/2023/06/gopher-wrangling.-effective-error-handling-in-go/
+ date: 2023-06-20T16:25:12Z
+ file: stephenn-com-kbiijs.txt
---
I find [Go][1] really compelling, even though it's not super applicable to my job. When evaluating a new tool, I find I'm weirdly biased to things written in Go.
@@ -66,9 +70,11 @@ I find [Go][1] really compelling, even though it's not super applicable to my jo
* [Why David Yach Loves Go][10]
* [One process programming notes (with Go and SQLite)][11]
* [Go Project Layout][12]
+* [Gopher Wrangling. Effective error handling in Go][13]
[8]: https://github.com/golang-standards/project-layout
[9]: https://changelog.com/gotime/278
[10]: https://cloud.google.com/blog/products/application-modernization/why-david-yach-loves-go
[11]: https://crawshaw.io/blog/one-process-programming-notes
[12]: https://medium.com/golang-learn/go-project-layout-e5213cdcfaa2
+[13]: https://stephenn.com/2023/06/gopher-wrangling.-effective-error-handling-in-go/
diff --git a/static/archive/stephenn-com-kbiijs.txt b/static/archive/stephenn-com-kbiijs.txt
@@ -0,0 +1,226 @@
+ [1]Stephen's Tech Blog
+
+ * [2]Webhook Wizard 🧙‍♂️
+
+ Gopher Wrangling. Effective error handling in Go
+
+ June 19, 2023 · 4 min · Stephen Nancekivell
+
+ Table of Contents
+
+ * [3]Guiding principle
+
+ [4]1. Always handle errors
+
+ [5]2. Log errors in one layer
+
+ [6]3. Returning async errors
+
+ [7]4. Wrapping errors
+
+ [8]5. Downgrade errors Warnings
+
+ When programming in Go, the amount of error handling is something that
+ slaps you in the face. Most API’s you deal with will expose errors. It
+ can become overwhelming, but with a few tips and a guiding principle we
+ can make handling errors easy, keep our code clean and give you the
+ confidence that nothing is breaking in production.
+
+ A cartoon of a crazy stressed programmer pulling their hair out in
+ front of lots of screens showing a error exclamation marks
+
+ A cartoon of a crazy stressed programmer pulling their hair out in
+ front of lots of screens showing a error exclamation marks
+
+Guiding principle[9]#
+
+ The goal for our error handling strategy is that it should require
+ minimal effort and provide an easy way to debug any errors that do
+ occur.
+
+ We wont cover strategies like retrying because they are less common and
+ also expose errors.
+
+1. Always handle errors[10]#
+
+ Always handle errors. Sometimes it’s tempting to skip one, you might
+ not expect that error to ever happen. But that’s why it’s an exception!
+ You need to handle it so that you can find out clearly if it ever does
+ happen.
+
+ If you don’t handle the error, the expected value will be something
+ else and just lead to another error that will be harder to debug, or
+ worse it could lead to data corruption.
+
+ In most cases to handle the error all you need to do is return it to
+ the caller of your method, where they can log it.
+
+ For example, when refreshing some data you might load it, then save it.
+ If you skip the error handling it could overwrite potentially useful
+ data with corrupt data.
+
+ 👎 Bad error handling
+func refresh() {
+ bytes, _ := loadData()
+ saveData(bytes)
+}
+
+ 👍 Good error handling
+func refresh() error {
+ bytes, err := loadData()
+ if err != nil {
+ return err
+ }
+ saveData(bytes)
+}
+
+2. Log errors in one layer[11]#
+
+ You always want to log your errors, ideally to something that will
+ notify you about the error, so you can fix it. There is no point
+ logging the error multiple times at every layer. Make it the top
+ layer’s responsibility and don’t log in any services or lower level
+ code.
+
+ Make sure your logging framework is including stack traces so you can
+ trace the error to its cause.
+
+ For example in a web app you would log the error in the http handler
+ when returning the Internal Server status code.
+
+ 👍 Good error handling
+func refresh() error {
+ bytes, err := loadData()
+ if err != nil {
+ return err
+ }
+ saveData(bytes)
+}
+
+func (h *handlers) handleRefreshRequest(w http.ResponseWriter, r *http.Request)
+{
+ err := refresh()
+ if err != nil {
+ log.Error("unexpected error processing request %w", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ w.WriteHeader(http.StatusOK)
+}
+
+3. Returning async errors[12]#
+
+ When processing data concurrently using a go-func’s, it can be annoying
+ to return the error. But if you don’t your app will be less
+ maintainable. To handle async errors, return them via a channel to the
+ calling thread.
+
+ 👎 Bad error handling
+func refreshManyConcurrently() {
+ go func(){
+ refresh(1)
+ }()
+
+ go func(){
+ refresh(2)
+ }()
+}
+
+ 👍 Good error handling
+func refreshManyConcurrently() error {
+ errors := make(chan error, 2)
+ go func(){
+ errors <- refresh(1)
+ }()
+
+ go func(){
+ errors <- refresh(2)
+ }()
+ return multierror.Combine(<-errors, <- errors)
+}
+
+ When calling functions that return a value and a possible error using a
+ type like Result[T], to wrap the response to pass on the channel.
+type Result[T any] struct {
+ Value T
+ Error error
+}
+
+4. Wrapping errors[13]#
+
+ Sometimes you want to add additional context to an error message. Eg to
+ include the id of the request that caused the error. You can use
+ fmt.error for this.
+err := saveToDb(user)
+if err != nil {
+ return fmt.errorf("unexpected error saving user. userId=%v error=%w", user.I
+d, err)
+}
+
+ Usually this isn’t necessary and its better to just return the error
+ unwrapped.
+
+5. Downgrade errors Warnings[14]#
+
+ There are types of errors that regularly occur during normal operation.
+ The system might not be able to prevent them all the time, but they
+ don’t need to investigate every time. It is better to treat them as
+ warnings rather than errors. These might be for things like timeouts or
+ intermittent connection errors.
+
+ 👍 Good error handling
+func (h *handlers) handleRefreshRequest(w http.ResponseWriter, r *http.Request)
+{
+ err := refresh()
+ if err != nil {
+ if err == context.DeadlineExceeded {
+ log.Warn("Timeout error processing request %w", err)
+ } else {
+ log.Error("unexpected error processing request %w", err)
+ }
+
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ w.WriteHeader(http.StatusOK)
+}
+
+ [15]Next »
+ How to Serve Web Sockets with Http4s
+
+ © 2023 [16]Stephen's Tech Blog
+
+References
+
+ Visible links:
+ 1. https://stephenn.com/
+ 2. https://webhookwizard.com/
+ 3. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L18069-7455TMP.html#guiding-principle
+ 4. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L18069-7455TMP.html#1-always-handle-errors
+ 5. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L18069-7455TMP.html#2-log-errors-in-one-layer
+ 6. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L18069-7455TMP.html#3-returning-async-errors
+ 7. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L18069-7455TMP.html#4-wrapping-errors
+ 8. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L18069-7455TMP.html#5-downgrade-errors-warnings
+ 9. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L18069-7455TMP.html#guiding-principle
+ 10. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L18069-7455TMP.html#1-always-handle-errors
+ 11. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L18069-7455TMP.html#2-log-errors-in-one-layer
+ 12. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L18069-7455TMP.html#3-returning-async-errors
+ 13. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L18069-7455TMP.html#4-wrapping-errors
+ 14. file:///var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L18069-7455TMP.html#5-downgrade-errors-warnings
+ 15. https://stephenn.com/2022/07/web-sockets-with-http4s/
+ 16. https://stephenn.com/
+
+ Hidden links:
+ 18. https://twitter.com/intent/tweet/?text=Gopher%20Wrangling.%20Effective%20error%20handling%20in%20Go&url=https%3a%2f%2fstephenn.com%2f2023%2f06%2fgopher-wrangling.-effective-error-handling-in-go%2f&hashtags=
+ 19. https://www.linkedin.com/shareArticle?mini=true&url=https%3a%2f%2fstephenn.com%2f2023%2f06%2fgopher-wrangling.-effective-error-handling-in-go%2f&title=Gopher%20Wrangling.%20Effective%20error%20handling%20in%20Go&summary=Gopher%20Wrangling.%20Effective%20error%20handling%20in%20Go&source=https%3a%2f%2fstephenn.com%2f2023%2f06%2fgopher-wrangling.-effective-error-handling-in-go%2f
+ 20. https://reddit.com/submit?url=https%3a%2f%2fstephenn.com%2f2023%2f06%2fgopher-wrangling.-effective-error-handling-in-go%2f&title=Gopher%20Wrangling.%20Effective%20error%20handling%20in%20Go
+ 21. https://facebook.com/sharer/sharer.php?u=https%3a%2f%2fstephenn.com%2f2023%2f06%2fgopher-wrangling.-effective-error-handling-in-go%2f
+ 22. https://api.whatsapp.com/send?text=Gopher%20Wrangling.%20Effective%20error%20handling%20in%20Go%20-%20https%3a%2f%2fstephenn.com%2f2023%2f06%2fgopher-wrangling.-effective-error-handling-in-go%2f
+ 23. https://telegram.me/share/url?text=Gopher%20Wrangling.%20Effective%20error%20handling%20in%20Go&url=https%3a%2f%2fstephenn.com%2f2023%2f06%2fgopher-wrangling.-effective-error-handling-in-go%2f
+ 24. file://localhost/var/folders/q9/qlz2w5251kzdfgn0np7z2s4c0000gn/T/L18069-7455TMP.html#top
+ 25. https://github.com/stephennancekivell
+ 26. https://twitter.com/hi_stephen_n
+ 27. https://www.linkedin.com/in/stephen-nancekivell-77003039
+ 28. https://stackoverflow.com/users/893854/stephen