perf(go): cache realtime plate lookups
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope"
|
||||
@@ -18,6 +19,69 @@ type PlateResolver interface {
|
||||
PlateByVIN(context.Context, string) (string, error)
|
||||
}
|
||||
|
||||
type CachedPlateResolver struct {
|
||||
delegate PlateResolver
|
||||
ttl time.Duration
|
||||
now func() time.Time
|
||||
mu sync.Mutex
|
||||
entries map[string]cachedPlateEntry
|
||||
}
|
||||
|
||||
type cachedPlateEntry struct {
|
||||
plate string
|
||||
notFound bool
|
||||
expiresAt time.Time
|
||||
}
|
||||
|
||||
func NewCachedPlateResolver(delegate PlateResolver, ttl time.Duration) *CachedPlateResolver {
|
||||
if delegate == nil {
|
||||
panic("cached plate resolver delegate must not be nil")
|
||||
}
|
||||
if ttl <= 0 {
|
||||
ttl = 10 * time.Minute
|
||||
}
|
||||
return &CachedPlateResolver{
|
||||
delegate: delegate,
|
||||
ttl: ttl,
|
||||
now: time.Now,
|
||||
entries: map[string]cachedPlateEntry{},
|
||||
}
|
||||
}
|
||||
|
||||
func (r *CachedPlateResolver) PlateByVIN(ctx context.Context, vin string) (string, error) {
|
||||
vin = strings.TrimSpace(vin)
|
||||
if vin == "" {
|
||||
return "", sql.ErrNoRows
|
||||
}
|
||||
now := r.now()
|
||||
r.mu.Lock()
|
||||
entry, ok := r.entries[vin]
|
||||
if ok && now.Before(entry.expiresAt) {
|
||||
r.mu.Unlock()
|
||||
if entry.notFound {
|
||||
return "", sql.ErrNoRows
|
||||
}
|
||||
return entry.plate, nil
|
||||
}
|
||||
r.mu.Unlock()
|
||||
|
||||
plate, err := r.delegate.PlateByVIN(ctx, vin)
|
||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return "", err
|
||||
}
|
||||
r.mu.Lock()
|
||||
r.entries[vin] = cachedPlateEntry{
|
||||
plate: strings.TrimSpace(plate),
|
||||
notFound: errors.Is(err, sql.ErrNoRows),
|
||||
expiresAt: now.Add(r.ttl),
|
||||
}
|
||||
r.mu.Unlock()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(plate), nil
|
||||
}
|
||||
|
||||
type SnapshotWriter struct {
|
||||
exec SnapshotExecer
|
||||
plateResolver PlateResolver
|
||||
|
||||
Reference in New Issue
Block a user