✨ Update dependencies, enhance NATS consumer configuration, and improve error handling in message processing. Introduce telemetry support with OpenTelemetry for tracing and metrics. Refactor README to include new configuration options and update tests for improved coverage of error scenarios.
This commit is contained in:
@@ -5,10 +5,16 @@ import (
|
||||
"caatsm/internal/adapter/mapper"
|
||||
"caatsm/internal/domain"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -30,8 +36,14 @@ func ProvideRepository(pool *pgxpool.Pool, logger *zap.Logger) (adapter.Reposito
|
||||
|
||||
// InsertOne inserts a single telegram message
|
||||
func (r *Repository) InsertOne(ctx context.Context, msg *domain.ParsedMessage) error {
|
||||
ctx, span := otel.Tracer("caatsm/postgres").Start(ctx, "Repository.InsertOne")
|
||||
defer span.End()
|
||||
span.SetAttributes(attribute.String("db.table", "aviation.telegrams"))
|
||||
|
||||
row, err := r.mapper.ToDBRow(msg)
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, err.Error())
|
||||
return fmt.Errorf("failed to map message to DB row: %w", err)
|
||||
}
|
||||
|
||||
@@ -39,18 +51,21 @@ func (r *Repository) InsertOne(ctx context.Context, msg *domain.ParsedMessage) e
|
||||
INSERT INTO aviation.telegrams (
|
||||
uuid, message_id, date_time, priority_indicator, primary_address,
|
||||
secondary_addresses, originator, originator_date_time, category,
|
||||
content, body_data, received_at, parsed_at, dispatched_at, need_dispatch
|
||||
content, body_data, status, error_reason,
|
||||
received_at, parsed_at, dispatched_at, need_dispatch
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15
|
||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17
|
||||
)
|
||||
ON CONFLICT (uuid) DO NOTHING
|
||||
`
|
||||
|
||||
tag, err := r.pool.Exec(ctx, query,
|
||||
row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8],
|
||||
row[9], row[10], row[11], row[12], row[13], row[14],
|
||||
row[9], row[10], row[11], row[12], row[13], row[14], row[15], row[16],
|
||||
)
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, err.Error())
|
||||
return fmt.Errorf("failed to insert message: %w", err)
|
||||
}
|
||||
|
||||
@@ -72,6 +87,10 @@ func (r *Repository) InsertOne(ctx context.Context, msg *domain.ParsedMessage) e
|
||||
|
||||
// InsertBatch inserts multiple telegram messages in a batch using CopyFrom
|
||||
func (r *Repository) InsertBatch(ctx context.Context, msgs []*domain.ParsedMessage) error {
|
||||
ctx, span := otel.Tracer("caatsm/postgres").Start(ctx, "Repository.InsertBatch")
|
||||
defer span.End()
|
||||
span.SetAttributes(attribute.String("db.table", "aviation.telegrams"))
|
||||
|
||||
if len(msgs) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -93,14 +112,18 @@ func (r *Repository) InsertBatch(ctx context.Context, msgs []*domain.ParsedMessa
|
||||
[]string{
|
||||
"uuid", "message_id", "date_time", "priority_indicator", "primary_address",
|
||||
"secondary_addresses", "originator", "originator_date_time", "category",
|
||||
"content", "body_data", "received_at", "parsed_at", "dispatched_at", "need_dispatch",
|
||||
"content", "body_data", "status", "error_reason",
|
||||
"received_at", "parsed_at", "dispatched_at", "need_dispatch",
|
||||
},
|
||||
pgx.CopyFromRows(rows),
|
||||
)
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, err.Error())
|
||||
return fmt.Errorf("failed to batch insert messages: %w", err)
|
||||
}
|
||||
|
||||
span.SetAttributes(attribute.Int64("db.inserted", copyCount))
|
||||
r.logger.Info("Batch inserted messages",
|
||||
zap.Int("count", int(copyCount)),
|
||||
zap.Int("attempted", len(msgs)),
|
||||
@@ -108,3 +131,69 @@ func (r *Repository) InsertBatch(ctx context.Context, msgs []*domain.ParsedMessa
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertRaw inserts a failed telegram into aviation.telegrams_raw for post-processing.
|
||||
func (r *Repository) InsertRaw(ctx context.Context, msg *domain.ParsedMessage) error {
|
||||
ctx, span := otel.Tracer("caatsm/postgres").Start(ctx, "Repository.InsertRaw")
|
||||
defer span.End()
|
||||
span.SetAttributes(attribute.String("db.table", "aviation.telegrams_raw"))
|
||||
|
||||
if msg == nil {
|
||||
err := fmt.Errorf("message is nil")
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, err.Error())
|
||||
return fmt.Errorf("message is nil")
|
||||
}
|
||||
if msg.Uuid == "" {
|
||||
msg.Uuid = uuid.NewString()
|
||||
}
|
||||
if msg.ReceivedAt.IsZero() {
|
||||
msg.ReceivedAt = time.Now()
|
||||
}
|
||||
|
||||
metadata := map[string]interface{}{
|
||||
"message_id": msg.MessageID,
|
||||
"category": msg.Category,
|
||||
"comments": msg.Comments,
|
||||
}
|
||||
metadataJSON, err := json.Marshal(metadata)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal metadata: %w", err)
|
||||
}
|
||||
|
||||
query := `
|
||||
INSERT INTO aviation.telegrams_raw (
|
||||
uuid, status, error_reason, content, received_at, metadata
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5, $6
|
||||
)
|
||||
ON CONFLICT (uuid) DO UPDATE
|
||||
SET status = EXCLUDED.status,
|
||||
error_reason = EXCLUDED.error_reason,
|
||||
content = EXCLUDED.content,
|
||||
received_at = EXCLUDED.received_at,
|
||||
metadata = EXCLUDED.metadata
|
||||
`
|
||||
|
||||
_, err = r.pool.Exec(ctx, query,
|
||||
msg.Uuid,
|
||||
string(msg.Status),
|
||||
msg.ErrorReason,
|
||||
msg.Content,
|
||||
msg.ReceivedAt,
|
||||
metadataJSON,
|
||||
)
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, err.Error())
|
||||
return fmt.Errorf("failed to insert raw telegram: %w", err)
|
||||
}
|
||||
|
||||
span.SetAttributes(attribute.String("telegram.uuid", msg.Uuid), attribute.String("telegram.status", string(msg.Status)))
|
||||
r.logger.Debug("Persisted raw telegram",
|
||||
zap.String("uuid", msg.Uuid),
|
||||
zap.String("status", string(msg.Status)),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user