context 標(biāo)準(zhǔn)庫(kù)的解決思路是:在整個(gè)樹(shù)形邏輯鏈條中锭碳,用上下文控制器 Context幽七,實(shí)現(xiàn)每個(gè)節(jié)點(diǎn)的信息傳遞和共享壹堰。
在 context 庫(kù)的官方文檔中有這么一句話:Do not store Contexts inside a struct type;instead, pass a Context explicitly to each function that needs it.The Context should be the first parameter.大意是說(shuō)建議我們?cè)O(shè)計(jì)函數(shù)的時(shí)候乙各,將 Context 作為函數(shù)的第一個(gè)參數(shù)谐岁。你能理解官方為什么如此建議醋奠,有哪些好處?可以結(jié)合你的工作經(jīng)驗(yàn)伊佃,說(shuō)說(shuō)自己的看法窜司。
context作為第一個(gè)參數(shù)在實(shí)際工作中是非常有用的一個(gè)實(shí)踐。不管我們是設(shè)計(jì)一個(gè)函數(shù)航揉,或者設(shè)計(jì)一個(gè)結(jié)構(gòu)體的方法塞祈,或者服務(wù)的時(shí)候,我們一旦養(yǎng)成了將第一個(gè)參數(shù)作為context的習(xí)慣帅涂,那么這個(gè)context在相互調(diào)用的時(shí)候议薪,就會(huì)傳遞下去尤蛮。這里會(huì)帶來(lái)幾個(gè)好處:
1 鏈路通用內(nèi)容傳遞。context中是可以通過(guò)WithValue方法將某些字段封裝在context里面斯议,并且傳遞的产捞。最常見(jiàn)的字段是traceId, spanId。而在日志中帶上這些ID哼御,再將日志收集起來(lái)坯临,我們就能進(jìn)行分析了。這也是我們現(xiàn)在比較流行的全鏈路分析的原理恋昼。
2 鏈路統(tǒng)一設(shè)置超時(shí)看靠。我們?cè)诙x一個(gè)服務(wù)的時(shí)候,將第一個(gè)參數(shù)固定設(shè)置為context焰雕,則可以通過(guò)這個(gè)context進(jìn)行超時(shí)設(shè)置衷笋,而這個(gè)超時(shí)設(shè)置,是由上游調(diào)用方進(jìn)行設(shè)置矩屁,這樣就形成了一個(gè)統(tǒng)一的超時(shí)設(shè)置機(jī)制辟宗。比如A設(shè)置了5s超時(shí),自己使用了1s吝秕,傳遞到下游B服務(wù)的時(shí)候泊脐,設(shè)置B的context超時(shí)時(shí)長(zhǎng)為4s。這樣全鏈路超時(shí)傳遞下去烁峭,就能保持統(tǒng)一設(shè)置了容客。
是的,請(qǐng)求控制和請(qǐng)求實(shí)現(xiàn)混在一起的情況约郁,后面引入middleware會(huì)改掉的缩挑。
PS:其實(shí)在 Golang 的設(shè)計(jì)中,每個(gè) Goroutine 都是獨(dú)立存在的鬓梅,父 Goroutine 一旦使用 Go 關(guān)鍵字開(kāi)啟了一個(gè)子 Goroutine供置,父子 Goroutine 就是平等存在的,他們互相不能干擾绽快。而在異常面前芥丧,所有 Goroutine 的異常都需要自己管理,不會(huì)存在父 Goroutine 捕獲子 Goroutine 異常的操作坊罢。所以切記:在 Golang 中续担,每個(gè) Goroutine 創(chuàng)建的時(shí)候,我們要使用 defer 和 recover 關(guān)鍵字為當(dāng)前 Goroutine 捕獲 panic 異常活孩,并進(jìn)行處理物遇,否則,任意一處 panic 就會(huì)導(dǎo)致整個(gè)進(jìn)程崩潰!