Share
Embed
開発期間数年のサービスの完成間際にcontext対応をぶち込む / introduce context.Context into long term project
kamakura.go #5 @ 鎌倉
acidlemon
June 22, 2019
Transcript
36 slides
-
͜Μʹͪʙ w ໘ന๏ਓΧϠοΫιʔγϟϧήʔϜࣄۀ෦ ήʔϜٕݚϦʔμʔ ֤ϓϩδΣΫτΛԣஅͰαϙʔτ͢ΔνʔϜ w ීஈओʹ(Pॻ͍ͨΓ1FSMॻ͍ͨΓ ۙ$Λॻ͍͍ͯΔ 6OJUZ
&NBDT͚ͩͬͨͲ࠷ۙ74$PEFͬͯΔ w חࡏॅ Ո͔Β͜ͷձ·Ͱెา !BDJEMFNPO -
93BZͰࢄτϨʔγϯά w !GVKJXBSB ͷ:"1$5PLZPͷൃදͳͲͰ͓ͳ͡Έ IUUQTTQFBLFSEFDLDPNGVKJXBSBZBQDUPLZP w ΧϠοΫͰࡢ͔Βෛՙࢼݧຊ൪ڥͷௐࠪʹ"8493BZΛ ར༻͍ͯ͠Δ
w ͕࠷ॳʹೖΕͨࣄྫ1FSM͕ͩͬͨɺࠓճ(PϓϩμΫτ (PͳΒ"84͕4%,Λग़͍ͯ͠ΔͷͰࣗલͰϥΠϒϥϦ࡞ΔΈ͍ͨ ͳ͜ͱ͠ͳͯ͘େৎ͜Εউͬͨͳʜʜ ϑϥάͷཱͭԻ -
93BZԿΛ͢Δ͔ w 8FCαʔϏεʹ͓͚Δ͔͔࣌ؒΔཁૉͷՄࢹԽ w جຊతʹ֎෦*0 σʔλϕʔεɺ,74ɺ)551ͳͲʜ ͕͔࣌ؒ ͔Δॲཧ w ηάϝϯτΛ࡞ͬͯ։࢝࣌ؒͱ
ऴྃ࣌ؒɺΤϥʔͳͲΛهͯ͠ૹΔ w "84͞ΜʹૹΓ͚ͭΔͱ͍͍ײ͡ʹ ՄࢹԽͯ͘͠ΕΔˠ͜Μͳײ͡ˠ -
͜Μͳײ͡ w YSBZ$BQUVSFʹDUYͱ࣮ߦ͍ͨ͠ॲཧΛแΜͩؔΛ͢ͱɺ $BQUVSF͕։࢝࣌ࠁͱऴྃ࣌ࠁΛDUYʹهͯ͘͠ΕΔ 93BZ)551ΫϥΠΞϯτͳͲ෦Ͱ͜ΕΛ͍ͬͯΔ func criticalSection(ctx context.Context) { //this
is an example of a subsegment xray.Capture(ctx, "GameModel.saveGame", func(ctx1 context.Context) error { var err error section.Lock() result := someLockedResource.Go() section.Unlock() xray.AddMetadata(ctx1, "ResourceResult", result) }) } IUUQTEPDTBXTBNB[PODPNKB@KQYSBZMBUFTUEFWHVJEFYSBZTELHPTVCTFHNFOUTIUNM -
DPOUFYUҾ͖ճ͠ϦϑΝΫλ w 3FEJT w SFEJHPΛར༻͍ͯͯ͠ɺࣗલͷ3FEJT$MJFOUͰXSBQ͍ͯͨ͠ ͷͰͦͷҾʹDPOUFYU$POUFYUΛՃ SFEJHP3FEJT$MVTUFSඇରԠͳͷͰޙʹHPSFEJTʹೖΕସ͑ͨ w 3FEJTͷ13
w 'MVFOU-PHHFS w ͜ΕࣗલͰXSBQͯͨ͠ͷͰҾʹDPOUFYU$POUFYUΛՃ w 'MVFOU-PHHFSͷ13 -
%#ΞΫηεͷDPOUFYUରԠ w HPSN HJUIVCDPNKJO[IVHPSN Λར༻ͯͨ͠ w ͦͦHPSN͕DPOUFYUରԠ͍ͯ͠ͳ͍ w W@EFWϒϥϯνͰDPOUFYUରԠ։ൃͯ͠Δ͚Ͳఀத w
ʜͱ͍͑93BZ͏ͷʹ%#ΞΫηεݟΒΕͳ͍ͷࠔΔ w ͍Ζ͍Ζௐࠪͯ͠Έͨ -
93BZ4%,͕༻ҙͯ͠Δͷ w ॻ͍ͯ͋Δ͜ͱʮ͓·͑ΒͨͿΜsql.OpenͰ%#ϓʔϧ࡞ͬͯΔ Αͳ ͦΕΛxray.SQLʹ͢Ε͍͍͚ͩͩͥʯ w ͳΔ΄ͲͬͯΈͨˠίϯύΠϧΤϥʔ w γάωνϟΛ֬ೝˠΓTRM%#͡Όͳͯ͘YSBZ%#ͩʜ package
xray func SQL(driver, dsn string) (*DB, error) -
YSBZ%#ͩ w HPSN42-$PNNPOͱ͍͏TRM%#ͷίϯςΩετͳ͠ϝιο υΛΠϯλϑΣʔεԽ͍ͯ͠Δ w YSBZ%#શ෦DUY͖ͰTRM%#ͷDUYϝιουΛ࣮͍ͯ͠Δ w ͭ·ΓΠϯλϑΣʔε͕ద߹͠ͳ͍ʜ type SQLCommon
interface { Exec(query string, args ...interface{}) (sql.Result, error) Prepare(query string) (*sql.Stmt, error) Query(query string, args ...interface{}) (*sql.Rows, error) QueryRow(query string, args ...interface{}) *sql.Row } package xray func (db *DB) Exec(ctx context.Context, query string, args ...interface{}) (sql.Result, error) func (db *DB) Prepare(ctx context.Context, query string) (*Stmt, error) func (db *DB) Query(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) func (db *DB) QueryRow(ctx context.Context, query string, args ...interface{}) *sql.Row HPSN YSBZ -
ཧͱݱ࣮ w HPSNʹ͢TRM%#తͳԿ͔ʹࡉΛͯ͠ɺHPSNΛXSBQͨ͠ϓ ϩδΣΫτͷ%#ΞΫηεΦϒδΣΫτ͔ΒͦͷDUYΛೖ͍ͨ͠ w ͱʹ͔͍͘Ζ͍ΖͬͯΈ·͕ͨ͠ɺͰ͖·ͤΜͰͨ͠ HPSN͕DPOUFYUରԠͯ͠ͳ͍ͷͰҾ͖ճ͕͠HPSNͰஅ͞Εͯ ͠·ͬͯͤͳ͍ʜΧελϜύϥϝʔλΛ͢ํ๏༻ҙ͞Εͯͳ͍ &YFD2VFSZͷBSHTͷ࠷ॳʹDUYͯ͠ϥούʔ͕͢Δࠇຐ๏Έ͍ͨͳͭࢼ͚ͨ͠Ͳͪΐͬͱແཧ͕͋ͬͨ ͋ͱɺTUSVDUͷϝϯόʹDUY࣋ͨͤΔํࣜTRM%#HPSN͕දݱ͢ΔͷίωΫγϣϯϓʔϧͰ͋ͬͯίωΫγϣϯ
Ͱͳ͍ʜͱ͍͏͜ͱ͔ΒHPSPVUJOFTBGFʹͳΒͳ͍ͷͰ͍͚ͬͯͳ͍Ϡπ -
(PSNͷϥούΛ࡞ͬͯࠐΉ w ಋೖखॱͱͯ͜͠Μͳ͔Μ͡ HPSN%#ͷϝιουͷ͏ͪͬͯΔͭΛશ෦ಉ͡γάωνϟ Ͱఆٛͯ͠ɺ·ͣίϯύΠϧΛ௨͢ தHPSNΛݺͿ͚ͩ ࣍ʹϥούͷୈҰҾʹશ෦ctx context.ContextΛՃ͢Δ (PSNΛݺͼग़ͯ͠Δ෦ͰຊʹେྔͷίϯύΠϧΤϥʔ͕Ͱ
ΔͷͰɺͦΕΛશ෦͢ 93BZͷ$BQUVSFΛϥούʔʹࠐΉ w ͱʹ͔͕͘େมͳͭͰ͢ -
Γͷ࡞ۀ w ͱʹ͔͘%#ݺͼग़͕͠େྔʹ͋ΔͷͰςΩετஔͳͲۦͭͭ͠ ͣͬͱϦϑΝΫλϦϯάͯ͠ςετΛճ͍ͯͨ͠ w ࣌ͷϝϞʹΑΔͱɺ$SFBUF%FMFUF&YFD'JOE'JSTU 3BX4BWFͷछͷϝιου͕߹ܭՕॴͰݺΕ͍ͯΔ w Օॴશ෦खͰͯ͠ɺ͞Βʹݺͼग़͠ݩ͕DUY࣋ͬͯͳ͔ͬͨ Βͦ͜·ͰDUYΛҾ͖ճͨ͢Ίʹݺͼग़͠ݩΛͬͯDUY͕ग़ͯ͘Δ·
ͰୈҰҾʹDUYՃ͢Δ࡞ۀ w ͞Βʹɺςετશ෦context.Background()ͯ͢͠࡞ۀ͕ඞཁ -
ϥούʔʹ$BQUVSFΛՃ w 93BZͷ$BQUVSFΛͦΕͧΕͷϝιουͰΔ w ͜ͷํࣜͰHPSN͕࣮ࡍʹ࣮ߦ͢Δ42-ΛऔΓग़ͤͳ͍ͨΊɺΘΓ ʹݺͼग़͠ͷҾͱίʔϧελοΫΛه // Exec ͩΑ func
(g *GormDB) Exec(ctx context.Context, sql string, values ...interface{}) *GormDB { if seg := xray.GetSegment(ctx); seg == nil { return g.wrap(g.db.Exec(sql, values...)) } var res *GormDB tmp := []interface{}{sql} tmp = append(tmp, values...) caller := traceCaller("Exec", tmp...) xray.Capture(ctx, g.name, func(ctx context.Context) error { g.recordSQL(ctx, caller) res = g.wrap(g.db.Exec(sql, values...)) return res.Error }) return res } 93BZະ༻࣌ 93BZ༻࣌ -
த w ίʔϧελοΫͱ42-ͷBSHTΛه w ه෦93BZ4%,ͷxray.DB.populate()Λࢀߟʹ func traceCaller(name string, args ...interface{})
string { pc, _, line, _ := runtime.Caller(2) f := runtime.FuncForPC(pc) return fmt.Sprintf("from %s(Line %d): %s(%s) ", f.Name(), line, name, argsString(args...)) } func (g *GormDB) recordSQL(ctx context.Context, info string) { seg := xray.GetSegment(ctx) typ := "master" if g.slave { typ = "slave" } seg.Lock() seg.Namespace = "remote" seg.GetSQL().ConnectionString = g.name seg.GetSQL().DatabaseType = typ seg.GetSQL().SanitizedQuery = info seg.Unlock() } -
ΫϥΠΞϯτஅʹΑΔDBODFM w ͦͦႈͳ࡞Γͷ"1*ʹͳ͍ͬͯΕɺαʔόʹϦΫΤετ͕དྷ ͨΒΫϥΠΞϯτʹؔͳ͘Γ͖ͬͨ΄͏͕Α͍ w SFRSFR8JUI$POUFYU OFX$UY Ͱࠩ͠ସ͑Ͱ͖Δ w ϦΫΤετࣗମͷλΠϜΞτඞཁͳͷͰɺSFRͷDUYΛܧঝͤͣ
ʹDPOUFYU#BDLHSPVOE Ͱ৽͍͠ίϯςΩετΛ࡞ͬͯλΠϜ ΞτΛઃఆ͢Δ w 4FSWFSΛ(SBDFGVMʹTIVUEPXO͢ΔͷϦΫΤετλΠϜΞ τ͘Β͍ͯ৽͍͠ϦΫΤετड͚͚ͳ͍ͷͰେৎ -
·ͱΊײ w ઌԆ͍ͯ͠͠Δͱޙ͔ΒϦϑΝΫλϦϯά͢Δίετ͕͍͢͝ࣄʹ ͳΔͷͰͬ͞͞ͱDPOUFYUରԠͨ͠΄͏͕Α͍ w ࠓ͔Β։ൃΛ࢝ΊΔͳΒɺ͍ͬͯΔ%#03.3FEJTΞΫηεͳ ͲͷύοέʔδDPOUFYUରԠ͍ͯ͠ΔͷΛબͿ͖ ٕज़બఆͷ༏ઌͱ͔ͯ͠ͳΓߴ͍ͱ͜ΖʹҐஔ͚ͮΔ͖ w
ઃܭํͱͯ͠ɺ ͨͱ͑ͦΕΛ࣮͢Δͱ͖ͬͯͳͯ͘ ϩ δοΫతʹ֎෦ͷ*0͕͋ΔͷDPOUFYUΛ͓ͯ͘͠ͱΑ͍ ͦ͏ͳΔͱ'MVFOUEͰϩάऔΔՄೳੑ͕͋Δͱ͜Ζશ෦ͦ͏ʜͱͳΔ͚Ͳͦ͏͍͏Μͩ