Upgrade to Pro — share decks privately, control downloads, hide ads and more …

context.Context is not just for cancelation

context.Context is not just for cancelation

Masayuki Izumi

July 26, 2018
Tweet

More Decks by Masayuki Izumi

Other Decks in Programming

Transcript

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

  2. 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 :)
  3. * 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
  4. * 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
  5. carries deadlines

  6. * 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
  7. carries cancelation signals

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

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

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

  11. &/%

  12. &/%

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

  14. * 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
  15. func WithValue(parent Context, key, val interface{}) Context func (Context) Value(key

    interface{}) interface{}
  16. ͳΜͰ΋͸͍ͬͯศརʢʁʣ 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"))
  17. func WithValue(parent Context, key, val interface{}) Context func (Context) Value(key

    interface{}) interface{}
  18. 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) }
  19. 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) }
  20. 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ͷॏෳΛ๷͝͏
  21. Ͱɼ

  22. ԿΛೖΕΔ͔ Կʹ࢖͏͔

  23. ! 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. }
  24. ! 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. }
  25. ܕ͕མͪΔ! JOUFSGBDF͕Θ͔ΓͮΒ͘ͳΔ!

  26. Կʹ࢖͑Δͷ͔!

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

    JOUFSGBDFʹυϝΠϯͱؔ܎ͳ͍΋ͷ͕͋ΔͱDPOGVTJOH!
  28. ϩδοΫͰ࢖ΘΕͳ͍΋ͷʁ ‣ ͳΜΒ͔ͷܭଌɾσʔλऩूʹ༻͍ΒΕΔ΋ͷ  FH  ϝτϦΫεऩू  αʔϏεؒ௨৴ͷτϨʔγϯά 

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

  30. 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
  31. 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
  32. Point ‣ ͋ΒΏΔϦΫΤετʹ͸ඞͣDPOUFYUΛ౉͓ͯ͘͠ Ͳ͏ͤλΠϜΞ΢τͱ͔ߟ͑ͳ͍ͱ͍͚ͳ͘ͳΔ ͱΓ͋͑ͣ౉͠ͱ͚͹ɼ৽͘͠ͳΜ͔ܭଌ͍ͨ͠ͱ͖ͱ͔ศར type PostStore interface { Create(ctx

    context.Context, title, body string, userID UserID) error }
  33. ‣ `context.Context`͸ΩϟϯηϧɾλΠϜΞ΢τͷͨΊͷϧʔϧ  ͋Δఔ౓Ҏ্େ͖ͳαʔϏεͩͱඞཁෆՄܽͳػೳ  ͚ͩͲɼͦΕ͚ͩ͡Όͳ͍ ‣ ϦΫΤετͷϝλ৘ใΛ͓࣋ͨͤͯ͘ͱ͍Ζ͍Ζܭଌ͢Δͱ͖ศར  3FRVFTU*%΍USBDJOHʹඞཁͳ৘ใॾʑɼϝτϦΫεऩूΦϒδΣΫτͳͲΛͬͦ͜Γ࣋ͪճͤΔ

    ‣ ϦΫΤετͬΆ͍ؔ਺ʹ͸`context.Context`Λඞͣ౉͢Α͏ʹ͢Δ  Ͳ͏ͤ͋ͱ͔Βཉ͘͠ͳΔͷͰɼ͍·͙͢࢖Θͳͯ͘΋࠷ॳ͔Β౉͓ͯ͜͠͏  ͋ͱ͔Β௥Ճ͢Δͷ͸୯७ʹखؒʹͳΔ
  34. https://www.wantedly.com/projects/223823