[{"data":1,"prerenderedAt":606},["ShallowReactive",2],{"content:\u002F2026\u002F02\u002Fgo-graceful-shutdown":3,"surround:\u002F2026\u002F02\u002Fgo-graceful-shutdown":595},{"id":4,"title":5,"body":6,"categories":574,"date":576,"description":577,"draft":578,"extension":579,"image":580,"meta":581,"navigation":429,"path":583,"permalink":580,"published":580,"readingTime":584,"recommend":580,"references":580,"seo":589,"sitemap":590,"stem":591,"tags":592,"type":593,"updated":576,"__hash__":594},"content\u002Fposts\u002F2026\u002F02\u002Fgo-graceful-shutdown.md","Golang中的优雅关闭与退出",{"type":7,"value":8,"toc":567},"minimark",[9,13,16,29,33,109,116,119,123,190,197,200,210,242,247,250,256,259,270,276,317,330,333,563],[10,11,12],"p",{},"在golang当中，我们经常需要在服务器关闭的那一瞬间去做一些操作",[10,14,15],{},"比如：",[17,18,19,23,26],"ul",{},[20,21,22],"li",{},"日志刷盘",[20,24,25],{},"关闭基础设施连接",[20,27,28],{},"销毁goroutine后台协程",[30,31,32],"h2",{"id":32},"优雅关闭和退出",[34,35,40],"pre",{"className":36,"code":37,"language":38,"meta":39,"style":39},"language-go shiki shiki-themes github-light github-dark","\u002F\u002F 优雅关闭和退出\nquit := make(chan os.Signal, 1)\nsignal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)\n","go","",[41,42,43,52,93],"code",{"__ignoreMap":39},[44,45,48],"span",{"class":46,"data-line":47,"line":47},"line",1,[44,49,51],{"class":50},"sJ8bj","\u002F\u002F 优雅关闭和退出\n",[44,53,55,59,63,67,71,74,77,80,83,86,90],{"class":46,"data-line":54,"line":54},2,[44,56,58],{"class":57},"sVt8B","quit ",[44,60,62],{"class":61},"szBVR",":=",[44,64,66],{"class":65},"sScJk"," make",[44,68,70],{"class":69},"sSDpw","(",[44,72,73],{"class":61},"chan",[44,75,76],{"class":65}," os",[44,78,79],{"class":57},".",[44,81,82],{"class":65},"Signal",[44,84,85],{"class":57},", ",[44,87,89],{"class":88},"sj4cs","1",[44,91,92],{"class":69},")\n",[44,94,96,99,102,104,107],{"class":46,"data-line":95,"line":95},3,[44,97,98],{"class":57},"signal.",[44,100,101],{"class":65},"Notify",[44,103,70],{"class":69},[44,105,106],{"class":57},"quit, syscall.SIGINT, syscall.SIGTERM",[44,108,92],{"class":69},[10,110,111,112,115],{},"这段代码的含义就是，创建一个监听系统信号的channel，在系统退出的时刻会向 ",[41,113,114],{"code":114},"quit"," 发送一个信号",[10,117,118],{},"这段代码主要监听两个信号，也是业界中常用的两个信号",[120,121,122],"h3",{"id":122},"对应的信号表格",[124,125,126,145],"table",{},[127,128,129],"thead",{},[130,131,132,136,139,142],"tr",{},[133,134,135],"th",{},"信号",[133,137,138],{},"来源",[133,140,141],{},"程序是否可捕获",[133,143,144],{},"常见用途",[146,147,148,163,176],"tbody",{},[130,149,150,154,157,160],{},[151,152,153],"td",{},"SIGINT",[151,155,156],{},"Ctrl+C",[151,158,159],{},"可以",[151,161,162],{},"本地手动停止",[130,164,165,168,171,173],{},[151,166,167],{},"SIGTERM",[151,169,170],{},"kill \u002F 容器停止 \u002F k8s pod 杀死",[151,172,159],{},[151,174,175],{},"优雅关闭",[130,177,178,181,184,187],{},[151,179,180],{},"SIGKILL",[151,182,183],{},"kill -9",[151,185,186],{},"不可以",[151,188,189],{},"强制杀死",[10,191,192,193,196],{},"不过需要注意的是，主要针对人为的",[41,194,195],{"code":195},"Ctrl + C","、进程被kill、docker容器被kill以及k8s pod被kill的信号",[120,198,199],{"id":199},"监测不到的signal",[10,201,202],{},[203,204,205,206,209],"strong",{},"vscode中的",[41,207,208],{"code":208},"dlv debug",", 直接 detach 或调用 ptrace 终止进程。",[17,211,212],{},[20,213,214,215,223,226,227,239,241],{},"真实结构是：",[34,216,221],{"className":217,"code":219,"language":220},[218],"language-text","dlv (调试器进程)\n   └── 被调试的 Go 进程\n","text",[41,222,219],{"__ignoreMap":39},[224,225],"br",{},"而且：",[17,228,229,236],{},[20,230,231,232,235],{},"dlv 通过 ",[203,233,234],{},"ptrace"," 控制 Go 进程",[20,237,238],{},"Go 进程是被“trace”的状态",[224,240],{},"暂停杀的是dlv调试程序，go进程无法监听到信号就被杀死了",[10,243,244],{},[203,245,246],{},"使用air的默认配置是无法触发优雅退出的",[10,248,249],{},"实际结构是：",[34,251,254],{"className":252,"code":253,"language":220,"meta":39},[218],"air 进程\n   └── 你的 Go 程序\n",[41,255,253],{"__ignoreMap":39},[10,257,258],{},"和 dlv 不同的是：",[17,260,261,264,267],{},[20,262,263],{},"air 不使用 ptrace",[20,265,266],{},"它只是一个普通父进程",[20,268,269],{},"通过 fork\u002Fexec 启动你的程序",[10,271,272,275],{},[203,273,274],{},"优雅退出","应该这样做",[34,277,281],{"className":278,"code":279,"language":280,"meta":39,"style":39},"language-toml shiki shiki-themes github-light github-dark","[build]\n  kill_delay = \"5s\"\n  send_interrupt = true\n","toml",[41,282,283,294,307],{"__ignoreMap":39},[44,284,285,288,291],{"class":46,"data-line":47,"line":47},[44,286,287],{"class":69},"[",[44,289,290],{"class":65},"build",[44,292,293],{"class":69},"]\n",[44,295,296,300,303],{"class":46,"data-line":54,"line":54},[44,297,299],{"class":298},"indent","  ",[44,301,302],{"class":57},"kill_delay = ",[44,304,306],{"class":305},"sZZnC","\"5s\"\n",[44,308,309,311,314],{"class":46,"data-line":95,"line":95},[44,310,299],{"class":298},[44,312,313],{"class":57},"send_interrupt = ",[44,315,316],{"class":88},"true\n",[10,318,319,320,322,323,326,327,329],{},"在",[41,321,290],{"code":290},"选项后修改这两个配置项，",[41,324,325],{"code":325},"send_interrupt","指的是给子进程发",[41,328,195],{"code":195},"的退出信号，并预留5s的时间给子进程。",[30,331,332],{"id":332},"示例代码",[34,334,336],{"className":36,"code":335,"language":38,"meta":39,"style":39},"func (a *App) Start() {\n\t\u002F\u002F 优雅关闭和退出\n\tquit := make(chan os.Signal, 1)\n\tsignal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)\n\n\tgo func() {\n\t\ta.engine.Run(fmt.Sprintf(\":%d\", conf.GetGlobalConfig().Server.Port))\n\t}()\n\n\t\u003C-quit\n\n\tlog.Println(\"exit wschat\")\n}\n",[41,337,338,375,382,409,424,431,449,499,513,518,534,539,557],{"__ignoreMap":39},[44,339,340,343,346,348,352,355,358,361,363,366,368,370,372],{"class":46,"data-line":47,"line":47},[44,341,342],{"class":61},"func",[44,344,345],{"class":57}," ",[44,347,70],{"class":69},[44,349,351],{"class":350},"s4XuR","a ",[44,353,354],{"class":61},"*",[44,356,357],{"class":65},"App",[44,359,360],{"class":69},")",[44,362,345],{"class":57},[44,364,365],{"class":65},"Start",[44,367,70],{"class":69},[44,369,360],{"class":69},[44,371,345],{"class":57},[44,373,374],{"class":69},"{\n",[44,376,377,380],{"class":46,"data-line":54,"line":54},[44,378,379],{"class":298},"\t",[44,381,51],{"class":50},[44,383,384,386,388,390,392,395,397,399,401,403,405,407],{"class":46,"data-line":95,"line":95},[44,385,379],{"class":298},[44,387,58],{"class":57},[44,389,62],{"class":61},[44,391,66],{"class":65},[44,393,70],{"class":394},"sJX2D",[44,396,73],{"class":61},[44,398,76],{"class":65},[44,400,79],{"class":57},[44,402,82],{"class":65},[44,404,85],{"class":57},[44,406,89],{"class":88},[44,408,92],{"class":394},[44,410,412,414,416,418,420,422],{"class":46,"data-line":411,"line":411},4,[44,413,379],{"class":298},[44,415,98],{"class":57},[44,417,101],{"class":65},[44,419,70],{"class":394},[44,421,106],{"class":57},[44,423,92],{"class":394},[44,425,427],{"class":46,"data-line":426,"line":426},5,[44,428,430],{"emptyLinePlaceholder":429},true,"\n",[44,432,434,436,438,441,443,445,447],{"class":46,"data-line":433,"line":433},6,[44,435,379],{"class":298},[44,437,38],{"class":61},[44,439,440],{"class":61}," func",[44,442,70],{"class":394},[44,444,360],{"class":394},[44,446,345],{"class":57},[44,448,374],{"class":394},[44,450,452,454,456,459,462,465,468,471,473,476,479,482,485,488,490,492,495,497],{"class":46,"data-line":451,"line":451},7,[44,453,379],{"class":298},[44,455,379],{"class":298},[44,457,458],{"class":57},"a.engine.",[44,460,461],{"class":65},"Run",[44,463,70],{"class":464},"sqkie",[44,466,467],{"class":57},"fmt.",[44,469,470],{"class":65},"Sprintf",[44,472,70],{"class":69},[44,474,475],{"class":305},"\":",[44,477,478],{"class":88},"%d",[44,480,481],{"class":305},"\"",[44,483,484],{"class":57},", conf.",[44,486,487],{"class":65},"GetGlobalConfig",[44,489,70],{"class":394},[44,491,360],{"class":394},[44,493,494],{"class":57},".Server.Port",[44,496,360],{"class":69},[44,498,92],{"class":464},[44,500,502,504,506,509,511],{"class":46,"data-line":501,"line":501},8,[44,503,379],{"class":298},[44,505,39],{"class":57},[44,507,508],{"class":394},"}",[44,510,70],{"class":394},[44,512,92],{"class":394},[44,514,516],{"class":46,"data-line":515,"line":515},9,[44,517,430],{"emptyLinePlaceholder":429},[44,519,521,523,525,528,531],{"class":46,"data-line":520,"line":520},10,[44,522,379],{"class":298},[44,524,39],{"class":61},[44,526,527],{"class":61},"\u003C",[44,529,530],{"class":61},"-",[44,532,533],{"class":57},"quit\n",[44,535,537],{"class":46,"data-line":536,"line":536},11,[44,538,430],{"emptyLinePlaceholder":429},[44,540,542,544,547,550,552,555],{"class":46,"data-line":541,"line":541},12,[44,543,379],{"class":298},[44,545,546],{"class":57},"log.",[44,548,549],{"class":65},"Println",[44,551,70],{"class":394},[44,553,554],{"class":305},"\"exit wschat\"",[44,556,92],{"class":394},[44,558,560],{"class":46,"data-line":559,"line":559},13,[44,561,562],{"class":69},"}\n",[564,565,566],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sSDpw, html code.shiki .sSDpw{--shiki-default:#005cc5;--shiki-dark:#79b8ff}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sJX2D, html code.shiki .sJX2D{--shiki-default:#e36209;--shiki-dark:#ffab70}html pre.shiki code .sqkie, html code.shiki .sqkie{--shiki-default:#5a32a3;--shiki-dark:#b392f0}",{"title":39,"searchDepth":411,"depth":411,"links":568},[569,573],{"id":32,"depth":54,"text":32,"children":570},[571,572],{"id":122,"depth":95,"text":122},{"id":199,"depth":95,"text":199},{"id":332,"depth":54,"text":332},[575],"Go语言","2026-02-19","Golang中的优雅关闭与退出，去做一些日志刷盘、关闭基础设施和goroutine连接的操作。",false,"md",null,{"slots":582},{},"\u002F2026\u002F02\u002Fgo-graceful-shutdown",{"text":585,"minutes":586,"time":587,"words":588},"3 min read",2.26,135600,452,{"title":5,"description":577},{"loc":583},"posts\u002F2026\u002F02\u002Fgo-graceful-shutdown",[38],"tech","YeN8JySlMPPlzySYxIpXKuO2UjfALrljs-TUWD9NrhY",[596,601],{"title":597,"path":598,"stem":599,"date":600,"type":593,"children":-1},"MySQL 用户与权限管理","\u002F2026\u002F02\u002Fmysql-dev-user","posts\u002F2026\u002F02\u002Fmysql-dev-user","2026-02-18",{"title":602,"path":603,"stem":604,"date":605,"type":593,"children":-1},"Go遍历时删除特定元素","\u002F2026\u002F02\u002Fgo-delete-element-in-range","posts\u002F2026\u002F02\u002Fgo-delete-element-in-range","2026-02-20",1786555054375]