53 lines
1.8 KiB
Go
53 lines
1.8 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"strconv"
|
|
"time"
|
|
|
|
"git.k6n.net/mats/platform/event"
|
|
invlevel "git.k6n.net/mats/platform/inventory"
|
|
"git.k6n.net/mats/platform/rabbit"
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
// emitLevelIfChanged classifies qty into a Level and emits an
|
|
// inventory.level_changed bus event only when it differs from the level last
|
|
// emitted for this SKU+location (the levelKey marker). Exact quantity never
|
|
// leaves the service; only the coarse crossing does. Shared by every write path
|
|
// (catalog feed, order.created commit). A nil conn (no bus) makes it a no-op.
|
|
func emitLevelIfChanged(ctx context.Context, rdb *redis.Client, conn *rabbit.Conn, country string, low int64, sku, loc string, qty int64) {
|
|
if conn == nil {
|
|
return
|
|
}
|
|
lvl := invlevel.LevelFor(qty, low)
|
|
// Atomic read-old + write-new of the level marker; redis.Nil means the
|
|
// marker didn't exist yet (first observation), which we treat as a crossing.
|
|
prev, err := rdb.SetArgs(ctx, levelKey(sku, loc), string(lvl), redis.SetArgs{Get: true}).Result()
|
|
if err != nil && err != redis.Nil {
|
|
log.Printf("inventory: level marker sku=%s: %v", sku, err)
|
|
return
|
|
}
|
|
if prev == string(lvl) {
|
|
return // no threshold crossing — stay off the bus
|
|
}
|
|
payload, err := invlevel.LevelChanged{SKU: sku, Location: loc, Level: lvl}.Encode()
|
|
if err != nil {
|
|
log.Printf("inventory: encode level payload sku=%s: %v", sku, err)
|
|
return
|
|
}
|
|
ev := event.Event{
|
|
ID: "invlvl-" + sku + "-" + loc + "-" + strconv.FormatInt(time.Now().UnixNano(), 36),
|
|
Type: event.InventoryLevelChanged,
|
|
Source: "inventory",
|
|
Subject: sku,
|
|
Payload: payload,
|
|
Time: time.Now(),
|
|
Meta: map[string]string{"country": country},
|
|
}
|
|
if err := rabbit.PublishEvent(conn.Connection(), "inventory", ev); err != nil {
|
|
log.Printf("inventory: publish level event sku=%s: %v", sku, err)
|
|
}
|
|
}
|