Slide 1

Slide 1 text

context.Context is not just for cancelation Go(Un)Conference 3kg @izumin5210

Slide 2

Slide 2 text

izumin5210 Engineer at Wantedly, Inc. Wantedly People ‣ Web Application Engineer - Server-side : Golang, Ruby, etc. - Web Frontend ‣ Interests in developer productivity on microservices ‣ I'll talk on builderscon Tokyo 2018 :)

Slide 3

Slide 3 text

* https://golang.org/pkg/context/ Package context defines the Context type, which carries deadlines, cancelation signals, and other request-scoped values across API boundaries and between processes.* context.Context

Slide 4

Slide 4 text

* https://golang.org/pkg/context/ Package context defines the Context type, which carries deadlines, cancelation signals, and other request-scoped values across API boundaries and between processes.* context.Context

Slide 5

Slide 5 text

carries deadlines

Slide 6

Slide 6 text

* https://golang.org/pkg/context/ Package context defines the Context type, which carries deadlines, cancelation signals, and other request-scoped values across API boundaries and between processes.* context.Context

Slide 7

Slide 7 text

carries cancelation signals

Slide 8

Slide 8 text

`context.Context`Usecases ‣ λΠϜΞ΢τ FHଞͷαʔό΁ͷϦΫΤετΛ౤͚͛ͨͲɼ஗͘ͳ͍ͬͯΔ৔߹͸ఘΊ͍ͨ ‣ Ωϟϯηϧͷ఻ൖ FHϨεϙϯε͸ฦ͠ऴΘͬͯΔͷʹHPSPVUJOF͕ࢮͳͣಈ͖ଓ͚͍ͯΔͷ͸ࠔΔ

Slide 9

Slide 9 text

Cancelation ‣ ద੾ͳDBODFMॲཧ͸લఏ ӈͷ͸ద౰͚ͩͲ ‣ ඪ४ύοέʔδͰ΋ଟ͘Ͱ࣮૷ࡁΈ `database/sql`ͱ͔`net/http`ͱ͔

Slide 10

Slide 10 text

࠷ߴʹศར ͔͍͖ͭͬͯ·͠ΐ͏

Slide 11

Slide 11 text

&/%

Slide 12

Slide 12 text

&/%

Slide 13

Slide 13 text

࢖͍ॴ͕Θ͔Βͳ͍๨ΕΒΕ͕ͪͳ ΋͏Ұͭͷػೳ

Slide 14

Slide 14 text

* https://golang.org/pkg/context/ Package context defines the Context type, which carries deadlines, cancelation signals, and other request-scoped values across API boundaries and between processes.* context.Context

Slide 15

Slide 15 text

func WithValue(parent Context, key, val interface{}) Context func (Context) Value(key interface{}) interface{}

Slide 16

Slide 16 text

ͳΜͰ΋͸͍ͬͯศརʢʁʣ ctx := context.TODO() ctx = context.WithValue(ctx, "ctxkey1", 100) ctx = context.WithValue(ctx, "ctxkey2", "foobar") // Output: // 100 foobar fmt.Println(ctx.Value("ctxkey1"), ctx.Value("ctxkey2"))

Slide 17

Slide 17 text

func WithValue(parent Context, key, val interface{}) Context func (Context) Value(key interface{}) interface{}

Slide 18

Slide 18 text

TFUUFSHFUUFSͰʢ͋Δఔ౓ʣܕΛकΖ͏ func GetFoo(ctx context.Context) string { if v, ok := ctx.Value("foo").(string); ok { return v } return "" } func SetFoo(ctx context.Context, v string) context.Context { return context.WithValue(ctx, "foo", v) }

Slide 19

Slide 19 text

func GetFoo(ctx context.Context) string { if v, ok := ctx.Value("foo").(string); ok { return v } return "" } func SetFoo(ctx context.Context, v string) context.Context { return context.WithValue(ctx, "foo", v) }

Slide 20

Slide 20 text

type ctxKeyFoo struct {} func GetFoo(ctx context.Context) string { if v, ok := ctx.Value(ctxKeyFoo{}).(string); ok { return v } return "" } func SetFoo(ctx context.Context, v string) context.Context { return context.WithValue(ctx, ctxKeyFoo{}, v) } LFZͷॏෳΛ๷͝͏

Slide 21

Slide 21 text

Ͱɼ

Slide 22

Slide 22 text

ԿΛೖΕΔ͔ Կʹ࢖͏͔

Slide 23

Slide 23 text

! Bad pattern " ϩδοΫʢυϝΠϯ ӬଓԽϩδοΫʣʹؔΘΔ΋ͷΛೖΕͳ͍ type PostStore interface { Create(ctx context.Context) error } func (s *postStoreImpl) Create(ctx context.Context) error { title := GetPostTitleFromContext(ctx) body := GetPostBodyFromContext(ctx) // snip. }

Slide 24

Slide 24 text

! Bad pattern " JOUFSGBDFఆ͚ٛͩͰ͸ύϥϝλʹԿ͕ඞཁ͔Θ͔Βͳ͍DBMMFS͕಺෦࣮૷ʹґଘͯ͠͠·͏ type PostStore interface { Create(ctx context.Context) error } func (s *postStoreImpl) Create(ctx context.Context) error { title := GetPostTitleFromContext(ctx) body := GetPostBodyFromContext(ctx) // snip. }

Slide 25

Slide 25 text

ܕ͕མͪΔ! JOUFSGBDF͕Θ͔ΓͮΒ͘ͳΔ!

Slide 26

Slide 26 text

Կʹ࢖͑Δͷ͔!

Slide 27

Slide 27 text

Idea - υϝΠϯͱؔ܎ͳ͍ϝλσʔλΛೖΕΔ ‣ ʢυϝΠϯɾӬଓԽɾFUDʣϩδοΫͰ࢖ΘΕͳ͍΋ͷͳΒྑ͍ ͦͷσʔλ͕ͳͯ͘΋ϩδοΫʹ͸Өڹ͕ग़ͳ͍΋ͷ ͦͷϩδοΫͱ͸ຊ࣭తʹؔ܎ͳ͍΋ͷ JOUFSGBDFʹυϝΠϯͱؔ܎ͳ͍΋ͷ͕͋ΔͱDPOGVTJOH!

Slide 28

Slide 28 text

ϩδοΫͰ࢖ΘΕͳ͍΋ͷʁ ‣ ͳΜΒ͔ͷܭଌɾσʔλऩूʹ༻͍ΒΕΔ΋ͷ FH ϝτϦΫεऩू αʔϏεؒ௨৴ͷτϨʔγϯά ΤϥʔϨϙʔςΟϯά

Slide 29

Slide 29 text

e.g. New Relic ʢϝτϦΫεऩूʣ ‣ αʔόͷϦΫΤετίϯςΩετ఻ൖ `sql.DB.QueryContext`ͳͲΛXSBQͯ͠ɼͦͷதͰTFHNFOUΛ࡞ΕΕ͹ྑ͍ ϦΫΤετΛड͚Δͱ͜ΖˠΫΤϦ౤͛Δͱ͜Ζ·ͰDPOUFYU఻ൖͤ͞Δ

Slide 30

Slide 30 text

e.g. New Relic `context.Context` ʹ `newrelic.Transaction` Λ֨ೲ͓ͯ͘͠ ʢNJEEMFXBSF `http.Handler` ΍H31$ͷJOUFSDFQUPSͰ΍Ε͹0,ʣ // SetTransaction stores newrelic transaction object into given context. func SetTransaction(ctx context.Context, txn newrelic.Transaction) context.Context { return context.WithValue(ctx, txnKey, txn) } https://godoc.org/github.com/izumin5210/newrelic-contrib-go/nrutil

Slide 31

Slide 31 text

e.g. New Relic + DB `sql.DB` ΛXSBQͯ͠ɼDPOUFYU͔Β5SBOTBDUJPOΛऔΓग़͠TFHNFOUΛ࡞Δ func (w *dbWrapper) QueryContext(ctx context.Context, q string, args ...interface{}) (*sql.Rows, error) { var ( rows *sql.Rows err error ) w.segment(ctx, q, args, func() { rows, err = w.original.QueryContext(ctx, q, args...) }) return rows, err } https://godoc.org/github.com/izumin5210/newrelic-contrib-go/nrsql

Slide 32

Slide 32 text

Point ‣ ͋ΒΏΔϦΫΤετʹ͸ඞͣDPOUFYUΛ౉͓ͯ͘͠ Ͳ͏ͤλΠϜΞ΢τͱ͔ߟ͑ͳ͍ͱ͍͚ͳ͘ͳΔ ͱΓ͋͑ͣ౉͠ͱ͚͹ɼ৽͘͠ͳΜ͔ܭଌ͍ͨ͠ͱ͖ͱ͔ศར type PostStore interface { Create(ctx context.Context, title, body string, userID UserID) error }

Slide 33

Slide 33 text

‣ `context.Context`͸ΩϟϯηϧɾλΠϜΞ΢τͷͨΊͷϧʔϧ ͋Δఔ౓Ҏ্େ͖ͳαʔϏεͩͱඞཁෆՄܽͳػೳ ͚ͩͲɼͦΕ͚ͩ͡Όͳ͍ ‣ ϦΫΤετͷϝλ৘ใΛ͓࣋ͨͤͯ͘ͱ͍Ζ͍Ζܭଌ͢Δͱ͖ศར 3FRVFTU*%΍USBDJOHʹඞཁͳ৘ใॾʑɼϝτϦΫεऩूΦϒδΣΫτͳͲΛͬͦ͜Γ࣋ͪճͤΔ ‣ ϦΫΤετͬΆ͍ؔ਺ʹ͸`context.Context`Λඞͣ౉͢Α͏ʹ͢Δ Ͳ͏ͤ͋ͱ͔Βཉ͘͠ͳΔͷͰɼ͍·͙͢࢖Θͳͯ͘΋࠷ॳ͔Β౉͓ͯ͜͠͏ ͋ͱ͔Β௥Ճ͢Δͷ͸୯७ʹखؒʹͳΔ

Slide 34

Slide 34 text

https://www.wantedly.com/projects/223823