Share
Embed
Transcript
21 slides
-
©Showcase Gig 自己紹介 • 照井寛也 • 株式会社Showcase Gig ◦ エンジニアリングオフィス
• Sendai.go オーガナイザー • x(twitter : @1019Hiroya) -
©Showcase Gig goroutineにおけるctx // 注文を永続化する処置 err := uc.OrderRepository.CreateOrder(ctx, order) if
err != nil { return err } go func() { // ユーザーに注文受付メールを送信する newCtx, cancel := context.WithCancel(context.Background()) defer cancel() err2 := uc.MailService.SendOrderReceivedMail(ctx, order) if err2 != nil { return err2 } }() return nil -
©Showcase Gig goroutineにおけるctx // 注文を永続化する処置 err := uc.OrderRepository.CreateOrder(ctx, order) if
err != nil { return err } go func() { // ユーザーに注文受付メールを送信する newCtx, cancel := context.WithCancel(context.Background()) defer cancel() err2 := uc.MailService.SendOrderReceivedMail(ctx, order) if err2 != nil { return err2 } }() return nil 新しいctxを発行する必要がある -
©Showcase Gig context.Background() // Background returns a non-nil, empty [Context].
It is never canceled, has no // values, and has no deadline. It is typically used by the main function, // initialization, and tests, and as the top-level Context for incoming // requests. func Background() Context { return backgroundCtx{} } https://pkg.go.dev/context#Background まっさらなcontextが生成される -
©Showcase Gig ctxにkey/valueを引き回すユースケース例 • ログ情報のため ◦ ユーザーID ◦ 注文番号 ◦
注文した店舗 ◦ …. • RLS(row level security)のため ◦ goroutineでもdbアクセスをしたい -
©Showcase Gig keyが分かっていれば入れ込むことはできる var keys = []key{ “order_id”, “restaurant_id”, }
func CloneBackgroundContext(ctx context.Context) context.Context { newCtx := context.Background() // KeyValueを引き継ぐ for _, key := range keys { value := ctx.Value(key) if value != nil { newCtx = context.WithValue(newCtx, key, value) } } return newCtx } -
©Showcase Gig keyが分かっていれば入れ込むことはできる var keys = []key{ “order_id”, “restaurant_id”, }
func CloneBackgroundContext(ctx context.Context) context.Context { newCtx := context.Background() // KeyValueを引き継ぐ for _, key := range keys { value := ctx.Value(key) if value != nil { newCtx = context.WithValue(newCtx, key, value) } } return newCtx } keyが増えた時に確実にメンテしないといけない -
©Showcase Gig type Context interface { Deadline() (deadline time.Time, ok
bool) Done() <-chan struct{} Err() error Value(key any) any } contextのinterface 4つのメソッドが満たせれば自分で作れる -
©Showcase Gig // 元々のctxを引き継ぐ type cloneCtx struct { originalCtx context.Context
// 元々のcontext newCtx context.Context // 新しく生成したcontext } func (c cloneCtx) Value(key any) any { return c.originalCtx.Value(key) } func (c cloneCtx) Deadline() (time.Time, bool) { return c.newCtx.Deadline() } func (c cloneCtx) Done() <-chan struct{} { return c.newCtx.Done() } func (c cloneCtx) Err() error { return c.newCtx.Err() } key/valueだけ親のctxを引き継ぐ -
©Showcase Gig // 元々のctxを引き継ぐ type cloneCtx struct { originalCtx context.Context
// 元々のcontext newCtx context.Context // 新しく生成したcontext } func (c cloneCtx) Value(key any) any { return c.originalCtx.Value(key) } func (c cloneCtx) Deadline() (time.Time, bool) { return c.newCtx.Deadline() } func (c cloneCtx) Done() <-chan struct{} { return c.newCtx.Done() } func (c cloneCtx) Err() error { return c.newCtx.Err() } key/valueだけ親のctxを引き継ぐ 元々のctxからkey/valueを取得する -
©Showcase Gig func DetachWithCancel(ctx context.Context) (context.Context, context.CancelFunc) { c, cancel
:= context.WithCancel(context.Background()) return cloneCtx{ originalCtx: ctx, newCtx: c, }, cancel } ただ、cancel()等は自分で作らないといけない -
©Showcase Gig func WithoutCancel(parent Context) Context { if parent ==
nil { panic("cannot create context from nil parent") } return withoutCancelCtx{parent} } 嬉しい https://pkg.go.dev/context@master#WithoutCancel -
©Showcase Gig 嬉しい type withoutCancelCtx struct { c Context }
func (withoutCancelCtx) Deadline() (deadline time.Time, ok bool) { return } func (withoutCancelCtx) Done() <-chan struct{} { return nil } func (withoutCancelCtx) Err() error { return nil } func (c withoutCancelCtx) Value(key any) any { return value(c, key) } func (c withoutCancelCtx) String() string { return contextName(c.c) + ".WithoutCancel" } -
©Showcase Gig こうなる // 注文を永続化する処置 err := uc.OrderRepository.CreateOrder(ctx, order) if
err != nil { return err } go func() { // ユーザーに注文受付メールを送信する newCtx, cancel := context.WithCancel(context.WithoutCancel(ctx)) defer cancel() err2 := uc.MailService.SendOrderReceivedMail(ctx, order) if err2 != nil { return err2 } }() return nil key/valueを引き継ぎつつ cancel処理を新たに作ってあげる