2021-03-30 16:05:40 +05:30
|
|
|
package lib
|
|
|
|
|
|
|
|
|
|
import (
|
2024-08-23 15:24:00 +05:30
|
|
|
"context"
|
2023-01-09 19:34:48 +05:30
|
|
|
"encoding/json"
|
|
|
|
|
"net/http"
|
2024-10-10 16:05:30 +05:30
|
|
|
"strings"
|
2023-02-02 14:00:32 +05:30
|
|
|
"time"
|
2021-03-30 16:05:40 +05:30
|
|
|
|
2024-08-23 15:24:00 +05:30
|
|
|
metrics "com.navi.medici.janus/instrumentation"
|
|
|
|
|
producer_module "com.navi.medici.janus/producer"
|
|
|
|
|
"com.navi.medici.janus/utils"
|
2021-03-30 16:05:40 +05:30
|
|
|
|
2024-08-23 15:24:00 +05:30
|
|
|
"github.com/Shopify/sarama"
|
|
|
|
|
"go.uber.org/zap"
|
2021-03-30 16:05:40 +05:30
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type RequestObject struct {
|
2023-01-09 19:34:48 +05:30
|
|
|
Body []byte
|
|
|
|
|
Header http.Header
|
2021-03-30 16:05:40 +05:30
|
|
|
}
|
|
|
|
|
|
2024-08-23 15:24:00 +05:30
|
|
|
type WorkerPool struct {
|
|
|
|
|
workers int
|
|
|
|
|
jobQueue chan RequestObject
|
|
|
|
|
logger *zap.Logger
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewWorkerPool(workers int) *WorkerPool {
|
|
|
|
|
return &WorkerPool{
|
|
|
|
|
workers: workers,
|
|
|
|
|
jobQueue: make(chan RequestObject, workers),
|
|
|
|
|
logger: utils.GetLogger(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (wp *WorkerPool) Start(ctx context.Context) {
|
|
|
|
|
for i := 0; i < wp.workers; i++ {
|
|
|
|
|
go wp.worker(ctx)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (wp *WorkerPool) worker(ctx context.Context) {
|
2023-01-09 19:34:48 +05:30
|
|
|
for {
|
2024-08-23 15:24:00 +05:30
|
|
|
select {
|
|
|
|
|
case <-ctx.Done():
|
|
|
|
|
return
|
|
|
|
|
case job := <-wp.jobQueue:
|
|
|
|
|
wp.processRequest(job)
|
|
|
|
|
}
|
2023-01-09 19:34:48 +05:30
|
|
|
}
|
2021-04-27 16:40:13 +05:30
|
|
|
}
|
|
|
|
|
|
2024-08-23 15:24:00 +05:30
|
|
|
func (wp *WorkerPool) AddJob(job RequestObject) {
|
|
|
|
|
wp.jobQueue <- job
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (wp *WorkerPool) processRequest(request RequestObject) {
|
|
|
|
|
defer func() {
|
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
|
wp.logger.Error("Recovered from panic in processRequest", zap.Any("panic", r))
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
2023-01-12 12:59:22 +05:30
|
|
|
eventProcessingStartTime := utils.NanosToMillis(time.Now().UnixNano())
|
2023-01-09 19:34:48 +05:30
|
|
|
messageBytes := request.Body
|
2021-04-27 16:40:13 +05:30
|
|
|
|
2023-01-09 19:34:48 +05:30
|
|
|
var result map[string]interface{}
|
2024-08-23 15:24:00 +05:30
|
|
|
if err := json.Unmarshal(messageBytes, &result); err != nil {
|
2024-08-26 14:31:21 +05:30
|
|
|
wp.logger.Error("Failed to unmarshal JSON",
|
|
|
|
|
zap.Error(err),
|
2024-08-26 16:49:15 +05:30
|
|
|
zap.String("client_addr", utils.GetClientIP(request.Header.Get("X-Forwarded-For"), "")),
|
2024-08-26 14:31:21 +05:30
|
|
|
zap.String("messageBytes", string(messageBytes)),
|
|
|
|
|
zap.Int("bytesLength", len(messageBytes)))
|
2024-08-23 15:24:00 +05:30
|
|
|
return
|
|
|
|
|
}
|
2021-04-27 16:40:13 +05:30
|
|
|
|
2024-08-23 15:24:00 +05:30
|
|
|
source := getSource(result)
|
2021-04-27 16:40:13 +05:30
|
|
|
|
2024-08-23 15:24:00 +05:30
|
|
|
recordValue := messageBytes
|
2025-01-16 21:04:39 +05:30
|
|
|
topics := getTopicsFromSource(source)
|
2021-04-27 16:40:13 +05:30
|
|
|
|
2025-01-16 21:04:39 +05:30
|
|
|
// Send to all designated topics
|
|
|
|
|
for _, topic := range topics {
|
|
|
|
|
message := &sarama.ProducerMessage{
|
|
|
|
|
Topic: topic,
|
|
|
|
|
Value: sarama.ByteEncoder(recordValue),
|
|
|
|
|
}
|
2023-01-09 18:15:35 +05:30
|
|
|
|
2025-01-16 21:04:39 +05:30
|
|
|
metrics.RequestCounter.WithLabelValues(source).Inc()
|
|
|
|
|
metrics.EventProcessingTimeHist.WithLabelValues(topic, source).Observe(float64(utils.NanosToMillis(time.Now().UnixNano()) - eventProcessingStartTime))
|
2024-08-23 15:24:00 +05:30
|
|
|
|
2025-01-16 21:04:39 +05:30
|
|
|
if err := producer_module.WriteMessageToKafkaAsync(message, source); err != nil {
|
|
|
|
|
wp.logger.Error("Failed to write message to Kafka",
|
|
|
|
|
zap.Error(err),
|
|
|
|
|
zap.String("source", source),
|
|
|
|
|
zap.String("topic", topic))
|
|
|
|
|
}
|
2024-08-23 15:24:00 +05:30
|
|
|
}
|
2021-03-30 16:05:40 +05:30
|
|
|
}
|
2021-04-27 16:40:13 +05:30
|
|
|
|
2025-01-16 21:04:39 +05:30
|
|
|
func getTopicsFromSource(source string) []string {
|
|
|
|
|
switch strings.ToUpper(source) {
|
|
|
|
|
case "LITMUS":
|
|
|
|
|
return []string{producer_module.GetLitmusClickstreamTopic()}
|
|
|
|
|
case "SYNCTIMER", "SYNCEVENTTASK", "IOSPULSETIMER":
|
|
|
|
|
// TODO : remove default topic for events from app source once users
|
|
|
|
|
// have migrated their pipelines to new topic
|
|
|
|
|
return []string{
|
|
|
|
|
producer_module.GetAppClickstreamTopic(),
|
|
|
|
|
producer_module.GetDefaultClickstreamTopic(),
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return []string{producer_module.GetDefaultClickstreamTopic()}
|
2024-10-10 16:05:30 +05:30
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-17 12:11:53 +05:30
|
|
|
func getSource(event map[string]interface{}) string {
|
|
|
|
|
if event["source"] == nil {
|
2023-01-17 12:33:47 +05:30
|
|
|
return "UNKNOWN"
|
2023-01-17 12:11:53 +05:30
|
|
|
}
|
|
|
|
|
return event["source"].(string)
|
2021-03-30 16:05:40 +05:30
|
|
|
}
|