{"id":20917536,"url":"https://github.com/impact-eintr/maddeningbugs","last_synced_at":"2026-04-27T10:31:38.984Z","repository":{"id":107515062,"uuid":"455175525","full_name":"impact-eintr/maddeningbugs","owner":"impact-eintr","description":"让我破大防的 bug 们","archived":false,"fork":false,"pushed_at":"2022-03-14T05:51:58.000Z","size":30,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-27T21:00:10.046Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/impact-eintr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-03T13:27:52.000Z","updated_at":"2022-02-05T09:08:36.000Z","dependencies_parsed_at":"2023-05-17T15:30:30.451Z","dependency_job_id":null,"html_url":"https://github.com/impact-eintr/maddeningbugs","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/impact-eintr/maddeningbugs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/impact-eintr%2Fmaddeningbugs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/impact-eintr%2Fmaddeningbugs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/impact-eintr%2Fmaddeningbugs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/impact-eintr%2Fmaddeningbugs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/impact-eintr","download_url":"https://codeload.github.com/impact-eintr/maddeningbugs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/impact-eintr%2Fmaddeningbugs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32333196,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"online","status_checked_at":"2026-04-27T02:00:06.769Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-18T16:33:59.815Z","updated_at":"2026-04-27T10:31:38.932Z","avatar_url":"https://github.com/impact-eintr.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# maddeningbugs\n让我破大防的 bug 们\n\n# 说明\n这个仓库用来记录一些让我当时百思不得其解的bug（可能后续也没有头绪），希望以后的我能解开它们（希望不要一直破防到我转行，tnnd，为什么我这么菜）\n\n## Bug No.1\n\n来自 impact-eintr/esq 单机版本 在没有生产者生产消息的时候，消费者直接退出会导致 监听消费端的 goroutine 无法退出 目前使用了一个全局 map[string]chan bool 为每个消费者 goroutine注册一个 exit channel 并在检测到链接断开的时候找到对应的 channel 让然后 close(exitCh)，这样未免太过丑陋，增加不必要的全局变量不说也使得扩展性直线下降(这以后还得同步这个map?)\n\n### 无法解决的问题\n\n为什么同一块内存(至少看上去是 因为地址相同) [mem].(T).func() 调用后实际上无效\n\n### 引申的知识点\n\n优雅停止 goroutine 这算是代码设计的欠缺吗？\n\n- 一种优秀的设计\n\n``` go\npackage main\n\nimport (\n\t\"log\"\n\t\"sync\"\n\t\"time\"\n)\n\ntype WaitGroupWrapper struct {\n\tsync.WaitGroup\n}\n\nfunc (w *WaitGroupWrapper) Wrap(cb func()) {\n\tw.Add(1)\n\tgo func() {\n\t\tcb()\n\t\tw.Done()\n\t}()\n}\n\ntype test struct {\n\texitChan chan struct{}\n\twg       WaitGroupWrapper\n}\n\nfunc (t *test) loop() {\n\tfor {\n\t\tselect {\n\t\tcase \u003c-t.exitChan:\n\t\t\tlog.Println(\"loop goroutine exit\")\n\t\t\treturn\n\t\tdefault:\n\t\t\tlog.Println(\"loop goroutine working\")\n\t\t\ttime.Sleep(time.Second)\n\t\t}\n\t}\n}\n\nfunc (t *test) exit() {\n\tclose(t.exitChan)\n\tt.wg.Wait()\n}\n\nfunc main() {\n\tt := \u0026test{exitChan: make(chan struct{})}\n\n\tt.wg.Wrap(t.loop)\n\n\ttime.Sleep(3 * time.Second)\n\n\tt.exit()\n\n\tlog.Println(\"main goroutine exit\")\n}\n\n```\n\n\n- 一个更加综合的案例 配合任务池\n\n``` go\npackage main\n\nimport (\n\t\"log\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\nconst MaxPoolSize = 8\n\ntype WaitGroupWrapper struct {\n\tsync.WaitGroup\n}\n\nfunc (w *WaitGroupWrapper) Wrap(cb func()) {\n\tw.Add(1)\n\tgo func() {\n\t\tcb()\n\t\tw.Done()\n\t}()\n}\n\ntype test struct {\n\texitChan chan struct{}\n\twg       WaitGroupWrapper\n\tpoolSize int32\n}\n\nfunc (t *test) loop() {\n\tdefer log.Println(\"loop goroutine exit\")\n\n\tselectNum := 20\n\tworkCh := make(chan string, selectNum)   // 用于分发topic给worker处理\n\tresponseCh := make(chan bool, selectNum) // 用于worker处理完任务后响应\n\tcloseCh := make(chan int)                // 用于通知worker退出\n\tt.resizePool(MaxPoolSize, workCh, closeCh, responseCh)\n\n\tscanTicker := time.NewTicker(1 * time.Second)\n\tfreshTicker := time.NewTicker(2 * time.Second)\n\tfor {\n\t\tselect {\n\t\tcase \u003c-t.exitChan:\n\t\t\tgoto exit\n\t\tcase \u003c-freshTicker.C:\n\t\t\tt.resizePool((MaxPoolSize + rand.Intn(10)), workCh, closeCh, responseCh)\n\t\tcase \u003c-scanTicker.C:\n\t\tdefault:\n\t\t\tlog.Println(\"loop goroutine working\")\n\t\t\ttime.Sleep(time.Second)\n\t\t}\n\n\t\tif rand.Intn(100)%2 == 0 {\n\t\t\tworkCh \u003c- \"Impact-EINTR\"\n\t\t} else {\n\t\t\tworkCh \u003c- \"233333\"\n\t\t}\n\n\t\tif ok := \u003c-responseCh; ok {\n\t\t\tlog.Println(\"正确的结果\")\n\t\t}\n\n\t}\n\nexit:\n\tclose(closeCh)\n\tscanTicker.Stop()\n\tfreshTicker.Stop()\n}\n\nfunc (t *test) delayLoop(workCh chan string, closeCh chan int, responseCh chan bool) {\n\tfor {\n\t\tselect {\n\t\tcase \u003c-closeCh:\n\t\t\tatomic.AddInt32(\u0026t.poolSize, -1)\n\t\t\treturn\n\t\tcase s := \u003c-workCh:\n\t\t\tlog.Printf(\"delay loop goroutine working, consume %s\\n\", s)\n\t\t\tif s == \"Impact-EINTR\" {\n\t\t\t\tresponseCh \u003c- true\n\t\t\t} else {\n\t\t\t\tresponseCh \u003c- false\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (t *test) resizePool(num int, workCh chan string, closeCh chan int, responseCh chan bool) {\n\tworkerNum := int32(float64(num) * 0.25)\n\tif workerNum \u003c 1 {\n\t\tworkerNum = 1\n\t}\n\n\tif workerNum \u003e t.poolSize {\n\t\tt.wg.Wrap(func() {\n\t\t\tt.delayLoop(workCh, closeCh, responseCh)\n\t\t})\n\t\tt.poolSize++\n\t}\n\n\tif workerNum \u003c t.poolSize {\n\t\tfor i := t.poolSize - workerNum; i \u003e 0; i-- {\n\t\t\tcloseCh \u003c- 1\n\t\t}\n\t}\n}\n\nfunc (t *test) exit() {\n\tclose(t.exitChan)\n\tt.wg.Wait()\n}\n\nfunc main() {\n\tt := \u0026test{exitChan: make(chan struct{})}\n\n\tt.wg.Wrap(t.loop)\n\n\ttime.Sleep(5 * time.Second)\n\n\tt.exit()\n\n\tlog.Println(\"main goroutine exit\")\n}\n\n```\n\n## Bug No.2\n\n这个 Bug 其实是我之前解决的,算是一种设计思路 场景是 使用 gin 进行路由处理的时候需要给处理方法传递一些数据\n\n``` go\nr := gin.Default()\n\nr.GET(\"/test\", func(c *gin.Context){\n\t// TODO\n})\n```\n\n\n但这样无法直接传递(不使用全局变量等方法的话)\n\n### 解决\n\n``` go\nr := gin.Default\n\ns := \"test\"\n\nr.GET(\"/test\", func(val string) gin.Handlefunc {\n\treturn func(c *gin.Context) {\n\t\tfmt.Println(val)\n\t}\n}(s))\n\n\n```\n\n\n### Notice No.3\n\n- 在for-select中，break只会影响到select，不会影响到for\n- 单独在select中是不能使用continue，会编译错误，只能用在for-select中。continue的语义就类似for中的语义，select后的代码不会被执行到。\n\n### Bug No.4\n- for select 中想要关闭管道来停止当前循环 应该再开一个goroutine？\n\n``` go\npackage main\n\nimport (\n\t\"log\"\n\t\"sync\"\n\t\"time\"\n)\n\ntype WaitGroupWrapper struct {\n\tsync.WaitGroup\n}\n\nfunc (w *WaitGroupWrapper) Wrap(cb func()) {\n\tw.Add(1)\n\tgo func() {\n\t\tcb()\n\t\tw.Done()\n\t}()\n}\n\ntype test struct {\n\texitChan chan struct{}\n\twg       WaitGroupWrapper\n}\n\nfunc (t *test) loop() {\n\tdefer log.Println(\"io goroutine exiting...\")\n\tfor {\n\t\tselect {\n\t\tcase \u003c-t.exitChan:\n\t\t\treturn\n\t\tdefault:\n\t\t\tlog.Println(\"loop goroutine working\")\n\t\t\ttime.Sleep(time.Second)\n\t\t}\n\t}\n}\n\nfunc (t *test) exit() {\n\tclose(t.exitChan)\n\tt.wg.Wait()\n}\n\nfunc main() {\n\tt := \u0026test{exitChan: make(chan struct{})}\n\n\tt.wg.Wrap(t.loop)\n\n\tt.wg.Wrap(func() {\n\t\tdefer log.Println(\"ticker goroutine exiting...\")\n\t\tc := time.NewTimer(3 * time.Second)\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase \u003c-t.exitChan:\n\t\t\t\treturn\n\t\t\tcase \u003c-c.C:\n\t\t\t\tgo t.exit()\n\t\t\t}\n\t\t}\n\t})\n\n\tfor i := 2; i \u003c 10; i++ {\n\t\tt.wg.Wrap(func() {\n\t\t\tdefer log.Println(\"test goroutine exiting...\")\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase \u003c-t.exitChan:\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\ttime.Sleep(5 * time.Second)\n\n\tlog.Println(\"main goroutine exit\")\n\n}\n\n```\n\n### Bug No.5\n- http 客户端不应该使用默认配置\n- 客户端的 resp.Body 一定要关掉! 否则会引发 `accept4: too many open files; retrying in 5m`\n\n``` go\nfunc Ping(url string) (bool) {\n    // create a new instance of http client struct, with a timeout of 2sec\n    client := http.Client{ Timeout: time.Second * 2 }\n\n    // simple GET request on given URL\n    res, err := client.Get(url)\n    if err != nil {\n        // if unable to GET given URL, then ping must fail\n        return false\n    }\n\n    // always close the response-body, even if content is not required\n    defer res.Body.Close()\n\n    // is the page status okay?\n    return res.StatusCode == http.StatusOK\n}\n```\n\n### TIPs NO.6\n替换多个文件中某个字符串\n\n-i 表示inplace edit，就地修改文件\n-r 表示搜索子目录\n-l 表示输出匹配的文件名\n\n``` sh\nsed -i \"s/entry/Entry/g\" `grep entry -rl .`\n```\n\n\n### Note No.7\n\n切片将第一个元素放到最后\n\n``` go\nvar client []*Client\n\n\tc := clients[0]\n\tif len(clients) \u003e 1 {\n\t\t// 已处理过的消息客户端重新放在最后\n\t\tclients = append(clients[1:], c)\n\t}\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimpact-eintr%2Fmaddeningbugs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fimpact-eintr%2Fmaddeningbugs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimpact-eintr%2Fmaddeningbugs/lists"}