Phase 4 — Performance: - F1: SSH DialPool with key-by-host pooling and 5min idle TTL - F2: In-memory entity lookup cache (TTL 60s, HTTP resolveEntityID) - F3: Trigram GIN indexes on entities.slug and entities.name (migration 031) - F4: Partial index on executions(classification_id) for auto-act (migration 032) - Added missing RunOutput and RunStreaming in actuator/ (E3 gap fill) Phase 6 — Infrastructure: - H1: Infisical image pinned to v0.99.1 - H2: execworker daemon — polls pending executions with per-execution advisory locks, recovers orphaned running executions, wired as docker-compose service - H3: splitSQL hardened with block comment and string-literal support, 6 new edge-case tests (11 total) - H4: Scheduler acquires pg_try_advisory_lock(0x01c05e6) at startup
61 lines
1.1 KiB
Go
61 lines
1.1 KiB
Go
package db
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type entityCacheEntry struct {
|
|
slug string
|
|
id string
|
|
attrs string
|
|
exp time.Time
|
|
}
|
|
|
|
type EntityCache struct {
|
|
mu sync.RWMutex
|
|
m map[string]entityCacheEntry
|
|
ttl time.Duration
|
|
}
|
|
|
|
func NewEntityCache(ttl time.Duration) *EntityCache {
|
|
return &EntityCache{
|
|
m: make(map[string]entityCacheEntry),
|
|
ttl: ttl,
|
|
}
|
|
}
|
|
|
|
func (c *EntityCache) GetSlug(id string) (string, bool) {
|
|
c.mu.RLock()
|
|
e, ok := c.m[id]
|
|
c.mu.RUnlock()
|
|
if !ok || time.Now().After(e.exp) {
|
|
return "", false
|
|
}
|
|
return e.slug, true
|
|
}
|
|
|
|
func (c *EntityCache) GetID(slug string) (string, bool) {
|
|
c.mu.RLock()
|
|
e, ok := c.m[slug]
|
|
c.mu.RUnlock()
|
|
if !ok || time.Now().After(e.exp) {
|
|
return "", false
|
|
}
|
|
return e.id, true
|
|
}
|
|
|
|
func (c *EntityCache) Set(slug, id, attrs string) {
|
|
exp := time.Now().Add(c.ttl)
|
|
c.mu.Lock()
|
|
c.m[slug] = entityCacheEntry{slug: slug, id: id, attrs: attrs, exp: exp}
|
|
c.m[id] = entityCacheEntry{slug: slug, id: id, attrs: attrs, exp: exp}
|
|
c.mu.Unlock()
|
|
}
|
|
|
|
func (c *EntityCache) Invalidate(slug, id string) {
|
|
c.mu.Lock()
|
|
delete(c.m, slug)
|
|
delete(c.m, id)
|
|
c.mu.Unlock()
|
|
} |