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

Subee: Pub/Sub Worker Framework Implementation

Subee: Pub/Sub Worker Framework Implementation

Hiroto Funakoshi

May 18, 2019
Tweet

Other Decks in Programming

Transcript

  1. $ whoami • Hiroto Funakoshi • @hlts2 • ۦ͚ग़͠ͷ৽ଔΤϯδχΞ •

    αʔϏεͷΞʔΩςΫνϟ΍ج൫։ൃʹڵຯ͕͋Δ
  2. $ whoami • Hiroto Funakoshi • @hlts2 • ۦ͚ग़͠ͷ৽ଔΤϯδχΞ •

    αʔϏεͷΞʔΩςΫνϟ΍ج൫։ൃʹڵຯ͕͋Δ WantedlyΠϯλʔϯͰ։ൃͨ͠OSSʹ͍ͭͯൃද͠·͢
  3. ϢʔεέʔεʢΠϕϯτ఻ൖʣ User Service A Service Pub/Sub B Service C Service

    ProfileΛߋ৽ υϝΠϯڥք͕Ͱ͖Δ ґଘ͢ΔαʔϏεΛ஌Βͳͯ͘΋͍͍
  4. ࣮૷ྫʢCloud Pub/Subʣ ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context,

    msg *pubsub.Message) { var post Post if err := json.Unmarshal(msg.Data, &post); err != nil { log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err := update(post); err != nil { log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() })
  5. ࣮૷ྫʢCloud Pub/Subʣ ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context,

    msg *pubsub.Message) { var post Post if err := json.Unmarshal(msg.Data, &post); err != nil { log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err := update(post); err != nil { log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() })
  6. ࣮૷ྫʢCloud Pub/Subʣ ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context,

    msg *pubsub.Message) { var post Post if err := json.Unmarshal(msg.Data, &post); err != nil { log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err := update(post); err != nil { log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() }) • ϝοηʔδΛਖ਼͘͠ॲཧग़དྷͨࣄΛPub/Subʹ఻͑Δ ‣ Pub/Sub͸ϝοηʔδΛ࡟আ͢Δ
 ɹɹɹɹϝοηʔδ͕࠶ૹ͞Εͳ͍
  7. ࣮૷ྫʢCloud Pub/Subʣ ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context,

    msg *pubsub.Message) { var post Post if err := json.Unmarshal(msg.Data, &post); err != nil { log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err := update(post); err != nil { log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() }) • ϝοηʔδΛਖ਼͘͠ॲཧग़དྷͳ͔ͬͨࣄΛPub/Subʹ఻͑Δ ‣ Pub/Sub͸ϝοηʔδΛ࡟আ͠ͳ͍
 ɹɹɹɹɹɹɹϝοηʔδ͕࠶ૹ͞ΕΔ
  8. Pub/Subಋೖͷ՝୊఺ • Worker࣮૷͕ඞཁ ‣ ୯Ұɾෳ਺ϝοηʔδΛॲཧ ‣ Consume࿙Εͳ͘Graceful Shutdown ‣ ϝτϦΫεͱΤϥʔϨϙʔςΟϯά

    • ຊ࣭Ͱ͸ͳ͍ίʔυʢج൫ͷ࣮૷ʣ͕૿͑Δ • ϚΠΫϩαʔϏεΛΨϯΨϯ࡞Δ૊৫Ͱ͸ 
 Workerͷίʔυ͕ڞ௨Խग़དྷ͍ͯͳ͍ͱࣅͨΑ͏ͳίʔυ͕ࢄཚ
  9. Pub/Subಋೖͷ՝୊఺ • Worker࣮૷͕ඞཁ ‣ ୯Ұɾෳ਺ϝοηʔδΛॲཧ ‣ Consume࿙Εͳ͘Graceful Shutdown ‣ ϝτϦΫεͱΤϥʔϨϙʔςΟϯά

    • ຊ࣭Ͱ͸ͳ͍ίʔυʢج൫ͷ࣮૷ʣ͕૿͑Δ • ϚΠΫϩαʔϏεΛΨϯΨϯ࡞Δ૊৫Ͱ͸ 
 Workerͷίʔυ͕ڞ௨Խग़དྷ͍ͯͳ͍ͱࣅͨΑ͏ͳίʔυ͕ࢄཚ Կ౓΋࣮૷͢Δͷʁ
  10. ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg *pubsub.Message)

    { var post Post if err := json.Unmarshal(msg.Data, &post); err != nil { msg.Ack() return } if err := update(post); err != nil { msg.Nack() return } msg.Ack() })
  11. ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg *pubsub.Message)

    { var post Post if err := json.Unmarshal(msg.Data, &post); err != nil { msg.Ack() return } if err := update(post); err != nil { msg.Nack() return } msg.Ack() }) LoggerΛ͍Ε͍ͨʂʂ
  12. ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg *pubsub.Message)

    { start := time.Now() log.Println("Receive message") log.Printf("Start consume process") defer log.Printf("End consume process. time: %v", time.Since(start)) var post Post if err := json.Unmarshal(msg.Data, &post); err != nil { log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err := update(post); err != nil { log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() })
  13. ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg *pubsub.Message)

    { start := time.Now() log.Println("Receive message") log.Printf("Start consume process") defer log.Printf("End consume process. time: %v", time.Since(start)) var post Post if err := json.Unmarshal(msg.Data, &post); err != nil { log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err := update(post); err != nil { log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() })
  14. ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg *pubsub.Message)

    { start := time.Now() log.Println("Receive message") log.Printf("Start consume process") defer log.Printf("End consume process. time: %v", time.Since(start)) var post Post if err := json.Unmarshal(msg.Data, &post); err != nil { log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err := update(post); err != nil { log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() }) Panic RecoverೖΕ͍ͨʂʂ
  15. ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg *pubsub.Message)

    { start := time.Now() log.Println("Receive message") log.Printf("Start consume process") defer func() { log.Printf("End consume process. time: %v", time.Since(start)) if p := recover(); p != nil { log.Printf("Revoery from panic: %v", p) } }() var post Post if err := json.Unmarshal(msg.Data, &post); err != nil { log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err := update(post); err != nil { log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() })
  16. ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg *pubsub.Message)

    { start := time.Now() log.Println("Receive message") log.Printf("Start consume process") defer func() { log.Printf("End consume process. time: %v", time.Since(start)) if p := recover(); p != nil { log.Printf("Revoery from panic: %v", p) } }() var post Post if err := json.Unmarshal(msg.Data, &post); err != nil { log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err := update(post); err != nil { log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() })
  17. ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg *pubsub.Message)

    { start := time.Now() log.Println("Receive message") log.Printf("Start consume process") defer func() { log.Printf("End consume process. time: %v", time.Since(start)) if p := recover(); p != nil { log.Printf("Revoery from panic: %v", p) } }() var post Post if err := json.Unmarshal(msg.Data, &post); err != nil { log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err := update(post); err != nil { log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() }) Error ReportingೖΕ͍ͨʂʂ
  18. raven.SetDSN("https://<key>:<secret>@sentry.io/<project>") ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg

    *pubsub.Message) { start := time.Now() log.Println("Receive message") log.Printf("Start consume process") defer func() { log.Printf("End consume process. time: %v", time.Since(start)) if p := recover(); p != nil { log.Printf("Revoery from panic: %v", p) } }() var post Post if err := json.Unmarshal(msg.Data, &post); err != nil { raven.CaptureError(err, nil) log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err := update(post); err != nil { raven.CaptureError(err, nil) log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() })
  19. raven.SetDSN("https://<key>:<secret>@sentry.io/<project>") ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg

    *pubsub.Message) { start := time.Now() log.Println("Receive message") log.Printf("Start consume process") defer func() { log.Printf("End consume process. time: %v", time.Since(start)) if p := recover(); p != nil { log.Printf("Revoery from panic: %v", p) } }() var post Post if err := json.Unmarshal(msg.Data, &post); err != nil { raven.CaptureError(err, nil) log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err := update(post); err != nil { raven.CaptureError(err, nil) log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() })
  20. raven.SetDSN("https://<key>:<secret>@sentry.io/<project>") ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg

    *pubsub.Message) { start := time.Now() log.Println("Receive message") log.Printf("Start consume process") defer func() { log.Printf("End consume process. time: %v", time.Since(start)) if p := recover(); p != nil { log.Printf("Revoery from panic: %v", p) } }() var post Post if err := json.Unmarshal(msg.Data, &post); err != nil { raven.CaptureError(err, nil) log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err := update(post); err != nil { raven.CaptureError(err, nil) log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() }) StatsΛऔΓ͍ͨʂʂ
  21. raven.SetDSN("https://<key>:<secret>@sentry.io/<project>") ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg

    *pubsub.Message) { start := time.Now() log.Println("Receive message") log.Printf("Start consume process") statsHandler.HandleProcess(ctx, &Receive{ BeginTime: start, }) defer func() { log.Printf("End consume process. time: %v", time.Since(start)) if p := recover(); p != nil { raven.CaptureError(err, nil) log.Printf("Revoery from panic: %v", p) } }() consumeBeginTime := time.Now() var err error ctx = statsHandler.TagProcess(ctx, &ConsumeBeginTag{}) defer func() { statsHandler.HandleProcess(ctx, &ConsumeEnd{ BeginTime: consumeBeginTime, EndTime: time.Now(), Error: err, }) statsHandler.HandleProcess(ctx, &End{ MsgCount: 1, BeginTime: start, EndTime: time.Now(), }) } var post Post if err = json.Unmarshal(msg.Data, &post); err != nil { raven.CaptureError(err, nil) log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err = update(post); err != nil { raven.CaptureError(err, nil) log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() })
  22. raven.SetDSN("https://<key>:<secret>@sentry.io/<project>") ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg

    *pubsub.Message) { start := time.Now() log.Println("Receive message") log.Printf("Start consume process") statsHandler.HandleProcess(ctx, &Receive{ BeginTime: start, }) defer func() { log.Printf("End consume process. time: %v", time.Since(start)) if p := recover(); p != nil { raven.CaptureError(err, nil) log.Printf("Revoery from panic: %v", p) } }() consumeBeginTime := time.Now() var err error ctx = statsHandler.TagProcess(ctx, &ConsumeBeginTag{}) defer func() { statsHandler.HandleProcess(ctx, &ConsumeEnd{ BeginTime: consumeBeginTime, EndTime: time.Now(), Error: err, }) statsHandler.HandleProcess(ctx, &End{ MsgCount: 1, BeginTime: start, EndTime: time.Now(), }) } var post Post if err = json.Unmarshal(msg.Data, &post); err != nil { raven.CaptureError(err, nil) log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err = update(post); err != nil { raven.CaptureError(err, nil) log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() })
  23. raven.SetDSN("https://<key>:<secret>@sentry.io/<project>") ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg

    *pubsub.Message) { start := time.Now() log.Println("Receive message") log.Printf("Start consume process") statsHandler.HandleProcess(ctx, &Receive{ BeginTime: start, }) defer func() { log.Printf("End consume process. time: %v", time.Since(start)) if p := recover(); p != nil { raven.CaptureError(err, nil) log.Printf("Revoery from panic: %v", p) } }() consumeBeginTime := time.Now() var err error ctx = statsHandler.TagProcess(ctx, &ConsumeBeginTag{}) defer func() { statsHandler.HandleProcess(ctx, &ConsumeEnd{ BeginTime: consumeBeginTime, EndTime: time.Now(), Error: err, }) statsHandler.HandleProcess(ctx, &End{ MsgCount: 1, BeginTime: start, EndTime: time.Now(), }) } var post Post if err = json.Unmarshal(msg.Data, &post); err != nil { raven.CaptureError(err, nil) log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err = update(post); err != nil { raven.CaptureError(err, nil) log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() }) ෳ਺ϝοηʔδΛॲཧ͍ͨ͠
  24. raven.SetDSN("https://<key>:<secret>@sentry.io/<project>") ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg

    *pubsub.Message) { start := time.Now() log.Println("Receive message") log.Printf("Start consume process") statsHandler.HandleProcess(ctx, &Receive{ BeginTime: start, }) defer func() { log.Printf("End consume process. time: %v", time.Since(start)) if p := recover(); p != nil { raven.CaptureError(err, nil) log.Printf("Revoery from panic: %v", p) } }() consumeBeginTime := time.Now() var err error ctx = statsHandler.TagProcess(ctx, &ConsumeBeginTag{}) defer func() { statsHandler.HandleProcess(ctx, &ConsumeEnd{ BeginTime: consumeBeginTime, EndTime: time.Now(), Error: err, }) statsHandler.HandleProcess(ctx, &End{ MsgCount: 1, BeginTime: start, EndTime: time.Now(), }) } var post Post if err = json.Unmarshal(msg.Data, &post); err != nil { raven.CaptureError(err, nil) log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err = update(post); err != nil { raven.CaptureError(err, nil) log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() })
  25. raven.SetDSN("https://<key>:<secret>@sentry.io/<project>") ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg

    *pubsub.Message) { start := time.Now() log.Println("Receive message") log.Printf("Start consume process") statsHandler.HandleProcess(ctx, &Receive{ BeginTime: start, }) defer func() { log.Printf("End consume process. time: %v", time.Since(start)) if p := recover(); p != nil { raven.CaptureError(err, nil) log.Printf("Revoery from panic: %v", p) } }() consumeBeginTime := time.Now() var err error ctx = statsHandler.TagProcess(ctx, &ConsumeBeginTag{}) defer func() { statsHandler.HandleProcess(ctx, &ConsumeEnd{ BeginTime: consumeBeginTime, EndTime: time.Now(), Error: err, }) statsHandler.HandleProcess(ctx, &End{ MsgCount: 1, BeginTime: start, EndTime: time.Now(), }) } var post Post if err = json.Unmarshal(msg.Data, &post); err != nil { raven.CaptureError(err, nil) log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err = update(post); err != nil { raven.CaptureError(err, nil) log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() })
  26. ཉ͔ͬͨ͠΋ͷ • ج൫ʢe.g. Workerʣ͕Ͳ͏ͳ͍ͬͯΔ͔ҙࣝͤͣʹ
 ΞϓϦέʔγϣϯίʔυʹूதͰ͖ΔΑ͏ͳ࢓૊Έ
 
 
 
 
 


    
 ΞϓϦέʔγϣϯ࣮૷ ج൫࣮૷ ج൫ͱΞϓϦέʔγϣϯίʔυ͕෼཭Ͱ͖͍ͯΔੈք ࡞Δͧ
  27. raven.SetDSN("https://<key>:<secret>@sentry.io/<project>") ctx := context.Background() err := subscription.Receive(ctx, func(ctx context.Context, msg

    *pubsub.Message) { start := time.Now() log.Println("Receive message") log.Printf("Start consume process") statsHandler.HandleProcess(ctx, &Receive{ BeginTime: start, }) defer func() { log.Printf("End consume process. time: %v", time.Since(start)) if p := recover(); p != nil { raven.CaptureError(err, nil) log.Printf("Revoery from panic: %v", p) } }() consumeBeginTime := time.Now() var err error ctx = statsHandler.TagProcess(ctx, &ConsumeBeginTag{}) defer func() { statsHandler.HandleProcess(ctx, &ConsumeEnd{ BeginTime: consumeBeginTime, EndTime: time.Now(), Error: err, }) statsHandler.HandleProcess(ctx, &End{ MsgCount: 1, BeginTime: start, EndTime: time.Now(), }) } var post Post if err = json.Unmarshal(msg.Data, &post); err != nil { raven.CaptureError(err, nil) log.Printf("could not decode message data: %#v", msg) msg.Ack() return } if err = update(post); err != nil { raven.CaptureError(err, nil) log.Printf("[ID %d] could not update: %v", post.Id, err) msg.Nack() return } msg.Ack() })
  28. subscriber, err := cloudpubsub.CreateSubscriber(ctx, "projectId", "subscriptionId") if err != nil

    { panic(err) } engine := subee.New( subscriber, NewConsumer(), NewStatshandler(), subee.WithConsumerInterceptors( subee_zap.ConsumerInterceptor(zap.Nop()), subee_recovery.ConsumerInterceptor( func(ctx context.Context, p interface{}) error { honybadger.Notify(p) return nil }, ), ) subee.WithStatsHandler( NewStatshandler(), ), ) engine.Start(ctx); type consumer struct {} func NewConsumer() subee.Consumer { return new(consumer) } func (c *consumer) Consume(ctx context.Context, msg subee.Message) error { return nil }
  29. subscriber, err := cloudpubsub.CreateSubscriber(ctx, "projectId", "subscriptionId") if err != nil

    { panic(err) } engine := subee.New( subscriber, NewConsumer(), NewStatshandler(), subee.WithConsumerInterceptors( subee_zap.ConsumerInterceptor(zap.Nop()), subee_recovery.ConsumerInterceptor( func(ctx context.Context, p interface{}) error { honybadger.Notify(p) return nil }, ), ) subee.WithStatsHandler( NewStatshandler(), ), ) engine.Start(ctx); type consumer struct {} func NewConsumer() subee.Consumer { return new(consumer) } func (c *consumer) Consume(ctx context.Context, msg subee.Message) error { return nil } ConsumerΛੜ੒
  30. type consumer struct {} func NewConsumer() subee.Consumer { return new(consumer)

    } func (c *consumer) Consume(ctx context.Context, msg subee.Message) error { return nil } subscriber, err := cloudpubsub.CreateSubscriber(ctx, "projectId", "subscriptionId") if err != nil { panic(err) } engine := subee.New( subscriber, NewConsumer(), NewStatshandler(), subee.WithConsumerInterceptors( subee_zap.ConsumerInterceptor(zap.Nop()), subee_recovery.ConsumerInterceptor( func(ctx context.Context, p interface{}) error { honybadger.Notify(p) return nil }, ), ) subee.WithStatsHandler( NewStatshandler(), ), ) engine.Start(ctx); Frameworkʹొ࿥͢Δ
  31. subscriber, err := cloudpubsub.CreateSubscriber(ctx, "projectId", "subscriptionId") if err != nil

    { panic(err) } engine := subee.New( subscriber, NewConsumer(), NewStatshandler(), subee.WithConsumerInterceptors( subee_zap.ConsumerInterceptor(zap.Nop()), subee_recovery.ConsumerInterceptor( func(ctx context.Context, p interface{}) error { honybadger.Notify(p) return nil }, ), ) subee.WithStatsHandler( NewStatshandler(), ), ) engine.Start(ctx);
  32. subscriber, err := cloudpubsub.CreateSubscriber(ctx, "projectId", "subscriptionId") if err != nil

    { panic(err) } engine := subee.New( subscriber, NewConsumer(), NewStatshandler(), subee.WithConsumerInterceptors( subee_zap.ConsumerInterceptor(zap.Nop()), subee_recovery.ConsumerInterceptor( func(ctx context.Context, p interface{}) error { honybadger.Notify(p) return nil }, ), ) subee.WithStatsHandler( NewStatshandler(), ), ) engine.Start(ctx);
  33. Subscriberͷੜ੒ • Pub/Sub͔ΒϝοηʔδΛऔಘ͢Δ੹຿Λ࣋ͭ • Cloud Pub/SubͷSubscriber࣮૷͸
 ϑϨʔϜϫʔΫʹ༻ҙ • ઃఆ஋ΛຒΊΔ͚ͩͰ
 Subscriberͷར༻͕Մೳ

    • ॊೈͳઃఆΛ͢ΔͨΊʹ
 Function OptionͰΧελϚΠζՄೳ subscriber, err := cloudpubsub.CreateSubscriber(ctx, “cloudpub-app", "subscription-id") if err != nil { panic(err) }
  34. subscriber, err := cloudpubsub.CreateSubscriber(ctx, "projectId", "subscriptionId") if err != nil

    { panic(err) } engine := subee.New( subscriber, NewConsumer(), NewStatshandler(), subee.WithConsumerInterceptors( subee_zap.ConsumerInterceptor(zap.Nop()), subee_recovery.ConsumerInterceptor( func(ctx context.Context, p interface{}) error { honybadger.Notify(p) return nil }, ), ) subee.WithStatsHandler( NewStatshandler(), ), ) engine.Start(ctx);
  35. subscriber, err := cloudpubsub.CreateSubscriber(ctx, "projectId", "subscriptionId") if err != nil

    { panic(err) } engine := subee.New( subscriber, NewConsumer(), NewStatshandler(), subee.WithConsumerInterceptors( subee_zap.ConsumerInterceptor(zap.Nop()), subee_recovery.ConsumerInterceptor( func(ctx context.Context, p interface{}) error { honybadger.Notify(p) return nil }, ), ) subee.WithStatsHandler( NewStatshandler(), ), ) engine.Start(ctx);
  36. subscriber, err := cloudpubsub.CreateSubscriber(ctx, "projectId", "subscriptionId") if err != nil

    { panic(err) } engine := subee.New( subscriber, NewConsumer(), NewStatshandler(), subee.WithConsumerInterceptors( subee_zap.ConsumerInterceptor(zap.Nop()), subee_recovery.ConsumerInterceptor( func(ctx context.Context, p interface{}) error { honybadger.Notify(p) return nil }, ), ) subee.WithStatsHandler( NewStatshandler(), ), ) engine.Start(ctx); type consumer struct {} func NewConsumer() subee.Consumer { return new(consumer) } func (c *consumer) Consume(ctx context.Context, msg subee.Message) error { return nil }
  37. Consumerͷੜ੒ • ୯ҰϝοηʔδΛॲཧ͢Δ
 ੹຿Λ࣋ͭ • ΞϓϦέʔγϣϯΤϯδχΞ͕
 ࣮ࡍʹ࣮૷͢Δ෦෼ type consumer struct

    {} func NewConsumer() subee.Consumer { return new(consumer) } func (c *consumer) Consume(ctx context.Context, msg subee.Message) error { return nil }
  38. subscriber, err := cloudpubsub.CreateSubscriber(ctx, "projectId", "subscriptionId") if err != nil

    { panic(err) } engine := subee.New( subscriber, NewConsumer(), NewStatshandler(), subee.WithConsumerInterceptors( subee_zap.ConsumerInterceptor(zap.Nop()), subee_recovery.ConsumerInterceptor( func(ctx context.Context, p interface{}) error { honybadger.Notify(p) return nil }, ), ) subee.WithStatsHandler( NewStatshandler(), ), ) engine.Start(ctx);
  39. subscriber, err := cloudpubsub.CreateSubscriber(ctx, "projectId", "subscriptionId") if err != nil

    { panic(err) } engine := subee.New( subscriber, NewConsumer(), NewStatshandler(), subee.WithConsumerInterceptors( subee_zap.ConsumerInterceptor(zap.Nop()), subee_recovery.ConsumerInterceptor( func(ctx context.Context, p interface{}) error { honybadger.Notify(p) return nil }, ), ) subee.WithStatsHandler( NewStatshandler(), ), ) engine.Start(ctx);
  40. InterceptorɾStatsHandlerͷੜ੒ • Interceptor ‣ Consumeલޙʹհೖ
 Ͱ͖Δ ‣ Logger, Recovery͸
 Frameworkʹ༻ҙ

    • StatsHandler ‣ ܭଌܥͷͨΊʹར༻ subee.WithConsumerInterceptors( subee_zap.ConsumerInterceptor(zap.Nop()), subee_recovery.ConsumerInterceptor( func(ctx context.Context, p interface{}) error { honybadger.Notify(p) return nil }, ), ), subee.WithStatsHandler( NewStatshandler(), )
  41. subscriber, err := cloudpubsub.CreateSubscriber(ctx, "projectId", "subscriptionId") if err != nil

    { panic(err) } engine := subee.New( subscriber, NewConsumer(), NewStatshandler(), subee.WithConsumerInterceptors( subee_zap.ConsumerInterceptor(zap.Nop()), subee_recovery.ConsumerInterceptor( func(ctx context.Context, p interface{}) error { honybadger.Notify(p) return nil }, ), ) subee.WithStatsHandler( NewStatshandler(), ), ) engine.Start(ctx);
  42. subscriber, err := cloudpubsub.CreateSubscriber(ctx, "projectId", "subscriptionId") if err != nil

    { panic(err) } engine := subee.New( subscriber, NewConsumer(), NewStatshandler(), subee.WithConsumerInterceptors( subee_zap.ConsumerInterceptor(zap.Nop()), subee_recovery.ConsumerInterceptor( func(ctx context.Context, p interface{}) error { honybadger.Notify(p) return nil }, ), ) subee.WithStatsHandler( NewStatshandler(), ), ) engine.Start(ctx);
  43. Engine • Subscribeͨ͠ϝοηʔδΛ
 Consumerʹ఻ൖ ‣ ୯ҰϝοηʔδΛ఻ൖ ‣ Bufferingͯ͠ෳ਺ϝοηʔδΛ఻ൖ • Graceful

    Shutdown engine := subee.New( subscriber, NewConsumer(), NewStatshandler(), subee.WithConsumerInterceptors( subee_zap.ConsumerInterceptor(zap.Nop()), subee_recovery.ConsumerInterceptor( func(ctx context.Context, p interface{}) error { honybadger.Notify(p) return nil }, ), ), subee.WithStatsHandler( NewStatshandler(), ), )
  44. Engine • Subscribeͨ͠ϝοηʔδΛ
 Consumerʹ఻ൖ ‣ ୯ҰϝοηʔδΛ఻ൖ ‣ Bufferingͯ͠ෳ਺ϝοηʔδΛ఻ൖ • Graceful

    Shutdown engine := subee.New( subscriber, NewConsumer(), NewStatshandler(), subee.WithConsumerInterceptors( subee_zap.ConsumerInterceptor(zap.Nop()), subee_recovery.ConsumerInterceptor( func(ctx context.Context, p interface{}) error { honybadger.Notify(p) return nil }, ), ), subee.WithStatsHandler( NewStatshandler(), ), ) InterfaceΛຬͨ͢ObjectΛొ࿥͢Δ͚ͩʂʂ
 ͋ͱ͸ྑ͍ײ͡ʹ΍ͬͯ͘ΕΔ
  45. ·ͱΊ • Subee: Pub/Sub Worker Framework Implementation ‣ WorkerपΓͷෳࡶ͞ΛӅṭ ‣

    ΞϓϦέʔγϣϯΤϯδχΞ͕ຊ࣭తͳ࣮૷ʹूதͰ͖Δ https://github.com/wantedly/subee