Subee: Pub/Sub Worker Framework Implementation

Subee: Pub/Sub Worker Framework Implementation

059f991223cfcea8980ff65b5b929541?s=128

Hiroto Funakoshi

May 18, 2019
Tweet

Transcript

  1. 2.

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

    αʔϏεͷΞʔΩςΫνϟ΍ج൫։ൃʹڵຯ͕͋Δ
  2. 3.

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

    αʔϏεͷΞʔΩςΫνϟ΍ج൫։ൃʹڵຯ͕͋Δ WantedlyΠϯλʔϯͰ։ൃͨ͠OSSʹ͍ͭͯൃද͠·͢
  3. 28.

    ϢʔεέʔεʢΠϕϯτ఻ൖʣ User Service A Service Pub/Sub B Service C Service

    ProfileΛߋ৽ υϝΠϯڥք͕Ͱ͖Δ ґଘ͢ΔαʔϏεΛ஌Βͳͯ͘΋͍͍
  4. 29.

    ࣮૷ྫʢ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. 30.

    ࣮૷ྫʢ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. 31.

    ࣮૷ྫʢ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. 32.

    ࣮૷ྫʢ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. 33.

    Pub/Subಋೖͷ՝୊఺ • Worker࣮૷͕ඞཁ ‣ ୯Ұɾෳ਺ϝοηʔδΛॲཧ ‣ Consume࿙Εͳ͘Graceful Shutdown ‣ ϝτϦΫεͱΤϥʔϨϙʔςΟϯά

    • ຊ࣭Ͱ͸ͳ͍ίʔυʢج൫ͷ࣮૷ʣ͕૿͑Δ • ϚΠΫϩαʔϏεΛΨϯΨϯ࡞Δ૊৫Ͱ͸ 
 Workerͷίʔυ͕ڞ௨Խग़དྷ͍ͯͳ͍ͱࣅͨΑ͏ͳίʔυ͕ࢄཚ
  9. 34.

    Pub/Subಋೖͷ՝୊఺ • Worker࣮૷͕ඞཁ ‣ ୯Ұɾෳ਺ϝοηʔδΛॲཧ ‣ Consume࿙Εͳ͘Graceful Shutdown ‣ ϝτϦΫεͱΤϥʔϨϙʔςΟϯά

    • ຊ࣭Ͱ͸ͳ͍ίʔυʢج൫ͷ࣮૷ʣ͕૿͑Δ • ϚΠΫϩαʔϏεΛΨϯΨϯ࡞Δ૊৫Ͱ͸ 
 Workerͷίʔυ͕ڞ௨Խग़དྷ͍ͯͳ͍ͱࣅͨΑ͏ͳίʔυ͕ࢄཚ Կ౓΋࣮૷͢Δͷʁ
  10. 35.

    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. 36.

    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. 37.

    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. 38.

    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. 39.

    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. 40.

    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. 41.

    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. 42.

    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. 43.

    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. 44.

    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. 45.

    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. 46.

    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. 47.

    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. 48.

    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. 49.
  25. 50.

    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. 51.

    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() })
  27. 54.
  28. 59.
  29. 60.
  30. 61.

    ཉ͔ͬͨ͠΋ͷ • ج൫ʢe.g. Workerʣ͕Ͳ͏ͳ͍ͬͯΔ͔ҙࣝͤͣʹ
 ΞϓϦέʔγϣϯίʔυʹूதͰ͖ΔΑ͏ͳ࢓૊Έ
 
 
 
 
 


    
 ΞϓϦέʔγϣϯ࣮૷ ج൫࣮૷ ج൫ͱΞϓϦέʔγϣϯίʔυ͕෼཭Ͱ͖͍ͯΔੈք ࡞Δͧ
  31. 68.

    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() })
  32. 70.

    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 }
  33. 71.

    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Λੜ੒
  34. 72.

    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ʹొ࿥͢Δ
  35. 73.

    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. 74.

    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);
  37. 75.

    Subscriberͷੜ੒ • Pub/Sub͔ΒϝοηʔδΛऔಘ͢Δ੹຿Λ࣋ͭ • Cloud Pub/SubͷSubscriber࣮૷͸
 ϑϨʔϜϫʔΫʹ༻ҙ • ઃఆ஋ΛຒΊΔ͚ͩͰ
 Subscriberͷར༻͕Մೳ

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

    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. 78.

    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. 79.

    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 }
  41. 80.

    Consumerͷੜ੒ • ୯ҰϝοηʔδΛॲཧ͢Δ
 ੹຿Λ࣋ͭ • ΞϓϦέʔγϣϯΤϯδχΞ͕
 ࣮ࡍʹ࣮૷͢Δ෦෼ type consumer struct

    {} func NewConsumer() subee.Consumer { return new(consumer) } func (c *consumer) Consume(ctx context.Context, msg subee.Message) error { return nil }
  42. 86.

    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. 87.

    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);
  44. 88.

    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(), )
  45. 92.

    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);
  46. 93.

    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);
  47. 94.

    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(), ), )
  48. 95.

    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Λొ࿥͢Δ͚ͩʂʂ
 ͋ͱ͸ྑ͍ײ͡ʹ΍ͬͯ͘ΕΔ
  49. 97.

    ·ͱΊ • Subee: Pub/Sub Worker Framework Implementation ‣ WorkerपΓͷෳࡶ͞ΛӅṭ ‣

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