2017-07-18 02:03:15 +00:00
|
|
|
package batchconsumer
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"io"
|
|
|
|
|
"log"
|
|
|
|
|
"os"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"gopkg.in/Clever/kayvee-go.v6/logger"
|
|
|
|
|
|
|
|
|
|
"github.com/Clever/amazon-kinesis-client-go/kcl"
|
|
|
|
|
)
|
|
|
|
|
|
2017-07-18 19:19:40 +00:00
|
|
|
// Config used for BatchConsumer constructor. Any empty fields are populated with defaults.
|
2017-07-18 02:03:15 +00:00
|
|
|
type Config struct {
|
2017-11-02 21:49:13 +00:00
|
|
|
// Logger for logging info / error logs.
|
|
|
|
|
Logger logger.KayveeLogger
|
|
|
|
|
|
|
|
|
|
// FailedLogsFile is where logs that failed to process are written.
|
|
|
|
|
FailedLogsFile string
|
2017-08-04 09:36:42 +00:00
|
|
|
|
2017-07-19 19:06:27 +00:00
|
|
|
// BatchInterval the upper bound on how often SendBatch is called with accumulated messages
|
|
|
|
|
BatchInterval time.Duration
|
|
|
|
|
// BatchCount is the number of messages that triggers a SendBatch call
|
|
|
|
|
BatchCount int
|
|
|
|
|
// BatchSize is the size of a batch in bytes that triggers a SendBatch call
|
|
|
|
|
BatchSize int
|
2017-07-18 02:03:15 +00:00
|
|
|
|
|
|
|
|
// ReadRateLimit the number of records read per seconds
|
|
|
|
|
ReadRateLimit int
|
|
|
|
|
// ReadBurstLimit the max number of tokens allowed by rate limiter
|
|
|
|
|
ReadBurstLimit int
|
|
|
|
|
|
2017-07-18 19:19:40 +00:00
|
|
|
// CheckpointFreq the frequency in which a checkpoint is saved
|
2017-07-18 02:03:15 +00:00
|
|
|
CheckpointFreq time.Duration
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-18 19:19:40 +00:00
|
|
|
// BatchConsumer is responsible for marshalling
|
2017-07-18 02:03:15 +00:00
|
|
|
type BatchConsumer struct {
|
2017-11-02 21:49:13 +00:00
|
|
|
kclProcess *kcl.KCLProcess
|
|
|
|
|
failedLogsFile *os.File
|
2017-07-18 02:03:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func withDefaults(config Config) Config {
|
2017-11-02 21:49:13 +00:00
|
|
|
if config.Logger == nil {
|
|
|
|
|
config.Logger = logger.New("amazon-kinesis-client-go")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if config.FailedLogsFile == "" {
|
|
|
|
|
config.FailedLogsFile = "/tmp/kcl-" + time.Now().Format(time.RFC3339)
|
2017-07-18 02:03:15 +00:00
|
|
|
}
|
|
|
|
|
|
2017-07-19 19:06:27 +00:00
|
|
|
if config.BatchInterval == 0 {
|
|
|
|
|
config.BatchInterval = 10 * time.Second
|
2017-07-18 02:03:15 +00:00
|
|
|
}
|
2017-07-19 19:06:27 +00:00
|
|
|
if config.BatchCount == 0 {
|
|
|
|
|
config.BatchCount = 500
|
2017-07-18 02:03:15 +00:00
|
|
|
}
|
2017-07-19 19:06:27 +00:00
|
|
|
if config.BatchSize == 0 {
|
|
|
|
|
config.BatchSize = 4 * 1024 * 1024
|
2017-07-18 02:03:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if config.ReadRateLimit == 0 {
|
2017-08-22 18:37:47 +00:00
|
|
|
config.ReadRateLimit = 2500
|
2017-07-18 02:03:15 +00:00
|
|
|
}
|
2017-07-18 19:53:25 +00:00
|
|
|
if config.ReadBurstLimit == 0 {
|
|
|
|
|
config.ReadBurstLimit = int(float64(config.ReadRateLimit)*1.2 + 0.5)
|
2017-07-18 02:03:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if config.CheckpointFreq == 0 {
|
|
|
|
|
config.CheckpointFreq = 60 * time.Second
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return config
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-18 19:19:40 +00:00
|
|
|
// NewBatchConsumerFromFiles creates a batch consumer. Readers/writers provided are used for
|
|
|
|
|
// interprocess communication.
|
2017-07-18 02:03:15 +00:00
|
|
|
func NewBatchConsumerFromFiles(
|
|
|
|
|
config Config, sender Sender, input io.Reader, output, errFile io.Writer,
|
|
|
|
|
) *BatchConsumer {
|
|
|
|
|
config = withDefaults(config)
|
|
|
|
|
|
2017-11-02 21:49:13 +00:00
|
|
|
file, err := os.OpenFile(config.FailedLogsFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
2017-07-18 02:03:15 +00:00
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("Unable to create log file: %s", err.Error())
|
|
|
|
|
}
|
2017-11-02 21:49:13 +00:00
|
|
|
failedLogsFile := logger.New("amazon-kinesis-client-go")
|
|
|
|
|
failedLogsFile.SetOutput(file)
|
2017-07-18 02:03:15 +00:00
|
|
|
|
2017-11-02 21:49:13 +00:00
|
|
|
wrt := NewBatchedWriter(config, sender, config.Logger, failedLogsFile)
|
2017-07-18 02:03:15 +00:00
|
|
|
kclProcess := kcl.New(input, output, errFile, wrt)
|
|
|
|
|
|
|
|
|
|
return &BatchConsumer{
|
2017-11-02 21:49:13 +00:00
|
|
|
kclProcess: kclProcess,
|
|
|
|
|
failedLogsFile: file,
|
2017-07-18 02:03:15 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-18 19:19:40 +00:00
|
|
|
// NewBatchConsumer creates batch consumer. Stdin, Stdout, and Stderr are used for interprocess
|
|
|
|
|
// communication.
|
2017-07-18 02:03:15 +00:00
|
|
|
func NewBatchConsumer(config Config, sender Sender) *BatchConsumer {
|
|
|
|
|
return NewBatchConsumerFromFiles(config, sender, os.Stdin, os.Stdout, os.Stderr)
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-18 19:19:40 +00:00
|
|
|
// Start when called, the consumer begins ingesting messages. This function blocks.
|
2017-07-18 02:03:15 +00:00
|
|
|
func (b *BatchConsumer) Start() {
|
|
|
|
|
b.kclProcess.Run()
|
2017-11-02 21:49:13 +00:00
|
|
|
b.failedLogsFile.Close()
|
2017-07-18 02:03:15 +00:00
|
|
|
}
|