2020-10-15 14:27:13 +02:00
|
|
|
package kafka
|
|
|
|
|
|
|
|
import (
|
2021-07-04 22:11:00 +02:00
|
|
|
"strings"
|
2021-05-30 14:51:56 +02:00
|
|
|
"time"
|
|
|
|
|
|
|
|
js "github.com/S7evinK/saramajetstream"
|
2020-10-15 14:27:13 +02:00
|
|
|
"github.com/Shopify/sarama"
|
2020-12-02 18:41:00 +01:00
|
|
|
"github.com/matrix-org/dendrite/setup/config"
|
2020-10-15 14:27:13 +02:00
|
|
|
"github.com/matrix-org/naffka"
|
|
|
|
naffkaStorage "github.com/matrix-org/naffka/storage"
|
2021-05-30 14:51:56 +02:00
|
|
|
"github.com/nats-io/nats.go"
|
2020-10-15 14:27:13 +02:00
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
|
|
|
func SetupConsumerProducer(cfg *config.Kafka) (sarama.Consumer, sarama.SyncProducer) {
|
|
|
|
if cfg.UseNaffka {
|
|
|
|
return setupNaffka(cfg)
|
|
|
|
}
|
2021-05-30 14:51:56 +02:00
|
|
|
if cfg.UseNATS {
|
|
|
|
return setupNATS(cfg)
|
|
|
|
}
|
2020-10-15 14:27:13 +02:00
|
|
|
return setupKafka(cfg)
|
|
|
|
}
|
|
|
|
|
|
|
|
// setupKafka creates kafka consumer/producer pair from the config.
|
|
|
|
func setupKafka(cfg *config.Kafka) (sarama.Consumer, sarama.SyncProducer) {
|
2020-10-27 15:11:37 +01:00
|
|
|
sCfg := sarama.NewConfig()
|
|
|
|
sCfg.Producer.MaxMessageBytes = *cfg.MaxMessageBytes
|
|
|
|
sCfg.Producer.Return.Successes = true
|
|
|
|
sCfg.Consumer.Fetch.Default = int32(*cfg.MaxMessageBytes)
|
|
|
|
|
|
|
|
consumer, err := sarama.NewConsumer(cfg.Addresses, sCfg)
|
2020-10-15 14:27:13 +02:00
|
|
|
if err != nil {
|
|
|
|
logrus.WithError(err).Panic("failed to start kafka consumer")
|
|
|
|
}
|
|
|
|
|
2020-10-27 15:11:37 +01:00
|
|
|
producer, err := sarama.NewSyncProducer(cfg.Addresses, sCfg)
|
2020-10-15 14:27:13 +02:00
|
|
|
if err != nil {
|
|
|
|
logrus.WithError(err).Panic("failed to setup kafka producers")
|
|
|
|
}
|
|
|
|
|
|
|
|
return consumer, producer
|
|
|
|
}
|
|
|
|
|
|
|
|
// In monolith mode with Naffka, we don't have the same constraints about
|
|
|
|
// consuming the same topic from more than one place like we do with Kafka.
|
|
|
|
// Therefore, we will only open one Naffka connection in case Naffka is
|
|
|
|
// running on SQLite.
|
|
|
|
var naffkaInstance *naffka.Naffka
|
|
|
|
|
|
|
|
// setupNaffka creates kafka consumer/producer pair from the config.
|
|
|
|
func setupNaffka(cfg *config.Kafka) (sarama.Consumer, sarama.SyncProducer) {
|
|
|
|
if naffkaInstance != nil {
|
|
|
|
return naffkaInstance, naffkaInstance
|
|
|
|
}
|
|
|
|
naffkaDB, err := naffkaStorage.NewDatabase(string(cfg.Database.ConnectionString))
|
|
|
|
if err != nil {
|
|
|
|
logrus.WithError(err).Panic("Failed to setup naffka database")
|
|
|
|
}
|
|
|
|
naffkaInstance, err = naffka.New(naffkaDB)
|
|
|
|
if err != nil {
|
|
|
|
logrus.WithError(err).Panic("Failed to setup naffka")
|
|
|
|
}
|
|
|
|
return naffkaInstance, naffkaInstance
|
|
|
|
}
|
2021-05-30 14:51:56 +02:00
|
|
|
|
|
|
|
func setupNATS(cfg *config.Kafka) (sarama.Consumer, sarama.SyncProducer) {
|
|
|
|
logrus.WithField("servers", cfg.Addresses).Debug("connecting to nats")
|
2021-07-04 22:11:00 +02:00
|
|
|
nc, err := nats.Connect(strings.Join(cfg.Addresses, ","))
|
2021-05-30 14:51:56 +02:00
|
|
|
if err != nil {
|
|
|
|
logrus.WithError(err).Panic("failed to connect to nats")
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
s, err := nc.JetStream()
|
|
|
|
if err != nil {
|
|
|
|
logrus.WithError(err).Panic("unable to get jetstream context")
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// create a stream for every topic
|
|
|
|
for _, topic := range config.KafkaTopics {
|
|
|
|
sn := cfg.TopicFor(topic)
|
|
|
|
stream, err := s.StreamInfo(sn)
|
|
|
|
if err != nil {
|
|
|
|
logrus.WithError(err).Warn("unable to get stream info")
|
|
|
|
}
|
|
|
|
|
|
|
|
if stream == nil {
|
|
|
|
maxLifeTime := time.Second * 0
|
|
|
|
|
|
|
|
// Typing events can be removed from the stream, as they are only relevant for a short time
|
|
|
|
if topic == config.TopicOutputTypingEvent {
|
2021-06-04 20:23:25 +02:00
|
|
|
maxLifeTime = time.Second * 60
|
2021-05-30 14:51:56 +02:00
|
|
|
}
|
2021-06-04 20:23:25 +02:00
|
|
|
_, err = s.AddStream(&nats.StreamConfig{
|
2021-05-30 14:51:56 +02:00
|
|
|
Name: sn,
|
|
|
|
Subjects: []string{topic},
|
|
|
|
MaxBytes: int64(*cfg.MaxMessageBytes),
|
|
|
|
MaxMsgSize: int32(*cfg.MaxMessageBytes),
|
|
|
|
MaxAge: maxLifeTime,
|
|
|
|
Duplicates: maxLifeTime / 2,
|
|
|
|
})
|
2021-06-04 20:23:25 +02:00
|
|
|
if err != nil {
|
|
|
|
logrus.WithError(err).WithField("stream", sn).Fatal("unable to add nats stream")
|
|
|
|
}
|
2021-05-30 14:51:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
consumer := js.NewJetStreamConsumer(s, cfg.TopicPrefix)
|
|
|
|
producer := js.NewJetStreamProducer(s, cfg.TopicPrefix)
|
|
|
|
return consumer, producer
|
|
|
|
}
|