Phase 4 (Performance) + Phase 6 (Infrastructure) completion
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
This commit is contained in:
@@ -281,6 +281,8 @@ func (s *Server) PatchEntity(ctx context.Context, req gen.PatchEntityRequestObje
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.entityCache.Invalidate(entity.Slug, entity.Id.String())
|
||||
|
||||
return gen.PatchEntity200JSONResponse{
|
||||
Body: entity,
|
||||
Headers: gen.PatchEntity200ResponseHeaders{ETag: `"` + strconv.Itoa(entity.Version) + `"`},
|
||||
|
||||
@@ -57,16 +57,27 @@ func clampLimit(l *int) int {
|
||||
// resolveEntityID resolves a UUID-or-slug path/query value to the entity UUID.
|
||||
func (s *Server) resolveEntityID(ctx context.Context, idOrSlug string) (uuid.UUID, error) {
|
||||
if id, err := uuid.Parse(idOrSlug); err == nil {
|
||||
if _, ok := s.entityCache.GetSlug(id.String()); ok {
|
||||
return id, nil
|
||||
}
|
||||
entity, err := sqlcgen.New(s.pool).GetEntityByID(ctx, id)
|
||||
if err != nil {
|
||||
return uuid.Nil, fmt.Errorf("%w: %s", domain.ErrNotFound, idOrSlug)
|
||||
}
|
||||
s.entityCache.Set(entity.Slug, entity.ID.String(), "")
|
||||
return entity.ID, nil
|
||||
}
|
||||
if cachedID, ok := s.entityCache.GetID(idOrSlug); ok {
|
||||
id, parseErr := uuid.Parse(cachedID)
|
||||
if parseErr == nil {
|
||||
return id, nil
|
||||
}
|
||||
}
|
||||
entity, err := sqlcgen.New(s.pool).GetEntityBySlug(ctx, idOrSlug)
|
||||
if err != nil {
|
||||
return uuid.Nil, fmt.Errorf("%w: %s", domain.ErrNotFound, idOrSlug)
|
||||
}
|
||||
s.entityCache.Set(entity.Slug, entity.ID.String(), "")
|
||||
return entity.ID, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ type Server struct {
|
||||
pool *db.Pool
|
||||
cfg config.Config
|
||||
secretsManager secrets.Backend
|
||||
entityCache *db.EntityCache
|
||||
sseBroker *sseBroker
|
||||
sseSubs map[*sseSubscriber]struct{}
|
||||
sseMu sync.Mutex
|
||||
@@ -69,10 +70,11 @@ type Server struct {
|
||||
// and pool.Close() deadlocks.
|
||||
func NewHandler(ctx context.Context, pool *db.Pool, cfg config.Config) http.Handler {
|
||||
s := &Server{
|
||||
pool: pool,
|
||||
cfg: cfg,
|
||||
sseBroker: newSSEBroker(10000),
|
||||
sseSubs: make(map[*sseSubscriber]struct{}),
|
||||
pool: pool,
|
||||
cfg: cfg,
|
||||
entityCache: db.NewEntityCache(60 * time.Second),
|
||||
sseBroker: newSSEBroker(10000),
|
||||
sseSubs: make(map[*sseSubscriber]struct{}),
|
||||
}
|
||||
|
||||
// Wire secrets backend: Infisical primary with SOPS DR fallback.
|
||||
|
||||
Reference in New Issue
Block a user