153 lines
3.5 KiB
Go
153 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/ThreeDotsLabs/watermill"
|
|
"github.com/ThreeDotsLabs/watermill-kafka/v3/pkg/kafka"
|
|
"github.com/ThreeDotsLabs/watermill/message"
|
|
"github.com/ThreeDotsLabs/watermill/message/router/middleware"
|
|
"github.com/ThreeDotsLabs/watermill/message/router/plugin"
|
|
)
|
|
|
|
var (
|
|
brokers = []string{"kafka:9092"}
|
|
consumeTopic = "events"
|
|
publishTopic = "events-processed"
|
|
|
|
logger = watermill.NewStdLogger(
|
|
true, // debug
|
|
false, // trace
|
|
)
|
|
marshaler = kafka.DefaultMarshaler{}
|
|
)
|
|
|
|
type event struct {
|
|
ID int `json:"id"`
|
|
}
|
|
|
|
type processedEvent struct {
|
|
ProcessedID int `json:"processed_id"`
|
|
Time time.Time `json:"time"`
|
|
}
|
|
|
|
func main() {
|
|
publisher := createPublisher()
|
|
|
|
// Subscriber is created with consumer group handler_1
|
|
subscriber := createSubscriber("handler_1")
|
|
|
|
router, err := message.NewRouter(message.RouterConfig{}, logger)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
router.AddPlugin(plugin.SignalsHandler)
|
|
router.AddMiddleware(middleware.Recoverer)
|
|
|
|
// Adding a handler (multiple handlers can be added)
|
|
router.AddHandler(
|
|
"handler_1", // handler name, must be unique
|
|
consumeTopic, // topic from which messages should be consumed
|
|
subscriber,
|
|
publishTopic, // topic to which messages should be published
|
|
publisher,
|
|
func(msg *message.Message) ([]*message.Message, error) {
|
|
consumedPayload := event{}
|
|
err := json.Unmarshal(msg.Payload, &consumedPayload)
|
|
if err != nil {
|
|
// When a handler returns an error, the default behavior is to send a Nack (negative-acknowledgement).
|
|
// The message will be processed again.
|
|
//
|
|
// You can change the default behaviour by using middlewares, like Retry or PoisonQueue.
|
|
// You can also implement your own middleware.
|
|
return nil, err
|
|
}
|
|
|
|
fmt.Printf("received event %+v\n", consumedPayload)
|
|
|
|
newPayload, err := json.Marshal(processedEvent{
|
|
ProcessedID: consumedPayload.ID,
|
|
Time: time.Now(),
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
newMessage := message.NewMessage(watermill.NewUUID(), newPayload)
|
|
|
|
return []*message.Message{newMessage}, nil
|
|
},
|
|
)
|
|
|
|
// Simulate incoming events in the background
|
|
go simulateEvents(publisher)
|
|
|
|
if err := router.Run(context.Background()); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
// createPublisher is a helper function that creates a Publisher, in this case - the Kafka Publisher.
|
|
func createPublisher() message.Publisher {
|
|
kafkaPublisher, err := kafka.NewPublisher(
|
|
kafka.PublisherConfig{
|
|
Brokers: brokers,
|
|
Marshaler: marshaler,
|
|
},
|
|
logger,
|
|
)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return kafkaPublisher
|
|
}
|
|
|
|
// createSubscriber is a helper function similar to the previous one, but in this case it creates a Subscriber.
|
|
func createSubscriber(consumerGroup string) message.Subscriber {
|
|
kafkaSubscriber, err := kafka.NewSubscriber(
|
|
kafka.SubscriberConfig{
|
|
Brokers: brokers,
|
|
Unmarshaler: marshaler,
|
|
ConsumerGroup: consumerGroup, // every handler will use a separate consumer group
|
|
},
|
|
logger,
|
|
)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return kafkaSubscriber
|
|
}
|
|
|
|
// simulateEvents produces events that will be later consumed.
|
|
func simulateEvents(publisher message.Publisher) {
|
|
i := 0
|
|
for {
|
|
e := event{
|
|
ID: i,
|
|
}
|
|
|
|
payload, err := json.Marshal(e)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
err = publisher.Publish(consumeTopic, message.NewMessage(
|
|
watermill.NewUUID(), // internal uuid of the message, useful for debugging
|
|
payload,
|
|
))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
i++
|
|
|
|
time.Sleep(time.Second)
|
|
}
|
|
}
|