feat(httpapi): harden control plane and speed up prefix refresh
Очередь job получила lease и fencing, телеметрия и прогресс deploy сохраняются, ревизия пишет manifest входов. Обновление префиксов не переписывает неизменённый снимок, большие наборы идут через COPY, а устаревшая ревизия не попадает в deploy. Бандл ноды кэшируется, prune и постановка job больше не держат горячий путь. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
924f111e48
commit
f8e0520817
197 files changed
+18655
-1416
No files matched your search
@@ -0,0 +1,127 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"evobgp/internal/store"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
func (p *Postgres) GetRenderGeneration(ctx context.Context, tenantID string) (int64, error) {
|
||||
var generation int64
|
||||
err := p.pool.QueryRow(ctx, `SELECT generation FROM tenant_render_generation WHERE tenant_id=$1::uuid`, tenantID).Scan(&generation)
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return 0, store.ErrNotFound
|
||||
}
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("repository: render generation: %w", err)
|
||||
}
|
||||
return generation, nil
|
||||
}
|
||||
|
||||
func (p *Postgres) ListModuleSnapshotHeaders(ctx context.Context, tenantID string) ([]store.ModuleSnapshotUse, error) {
|
||||
rows, err := p.pool.Query(ctx, `
|
||||
SELECT module_id::text, snapshot_version, COALESCE(input_hash, '')
|
||||
FROM module_prefix_snapshot
|
||||
WHERE tenant_id = $1::uuid
|
||||
ORDER BY module_id`, tenantID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("repository: list snapshot headers: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []store.ModuleSnapshotUse
|
||||
for rows.Next() {
|
||||
var item store.ModuleSnapshotUse
|
||||
if err := rows.Scan(&item.ModuleID, &item.SnapshotVersion, &item.InputHash); err != nil {
|
||||
return nil, fmt.Errorf("repository: scan snapshot header: %w", err)
|
||||
}
|
||||
out = append(out, item)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("repository: iterate snapshot headers: %w", err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (p *Postgres) LatestRenderManifest(ctx context.Context, tenantID string) (*store.RenderManifestRecord, bool, error) {
|
||||
var revID string
|
||||
var gen *int64
|
||||
var raw []byte
|
||||
err := p.pool.QueryRow(ctx, `
|
||||
SELECT cr.id::text, m.config_generation, m.manifest_json
|
||||
FROM config_revision cr
|
||||
LEFT JOIN render_revision_manifest m ON m.revision_id = cr.id
|
||||
WHERE cr.tenant_id = $1::uuid
|
||||
ORDER BY cr.created_at DESC, cr.id DESC
|
||||
LIMIT 1`, tenantID).Scan(&revID, &gen, &raw)
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return nil, false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("repository: latest render manifest: %w", err)
|
||||
}
|
||||
if gen == nil || len(raw) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
var doc struct {
|
||||
Snapshots []store.ModuleSnapshotUse `json:"snapshots"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &doc); err != nil {
|
||||
return nil, false, fmt.Errorf("repository: decode render manifest: %w", err)
|
||||
}
|
||||
return &store.RenderManifestRecord{
|
||||
RevisionID: revID,
|
||||
Generation: *gen,
|
||||
Snapshots: doc.Snapshots,
|
||||
}, true, nil
|
||||
}
|
||||
|
||||
func insertRenderManifestTx(ctx context.Context, tx pgx.Tx, revisionID, tenantID string) error {
|
||||
var gen int64
|
||||
err := tx.QueryRow(ctx, `
|
||||
SELECT generation FROM tenant_render_generation
|
||||
WHERE tenant_id = $1::uuid
|
||||
FOR UPDATE`, tenantID).Scan(&gen)
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
gen = 1
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("repository: lock render generation: %w", err)
|
||||
}
|
||||
rows, err := tx.Query(ctx, `
|
||||
SELECT module_id::text, snapshot_version, COALESCE(input_hash, '')
|
||||
FROM module_prefix_snapshot
|
||||
WHERE tenant_id = $1::uuid
|
||||
ORDER BY module_id`, tenantID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("repository: read snapshot versions: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
var snaps []store.ModuleSnapshotUse
|
||||
for rows.Next() {
|
||||
var item store.ModuleSnapshotUse
|
||||
if err := rows.Scan(&item.ModuleID, &item.SnapshotVersion, &item.InputHash); err != nil {
|
||||
return fmt.Errorf("repository: scan snapshot version: %w", err)
|
||||
}
|
||||
snaps = append(snaps, item)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return fmt.Errorf("repository: iterate snapshot versions: %w", err)
|
||||
}
|
||||
body, err := json.Marshal(struct {
|
||||
Snapshots []store.ModuleSnapshotUse `json:"snapshots"`
|
||||
}{Snapshots: snaps})
|
||||
if err != nil {
|
||||
return fmt.Errorf("repository: encode render manifest: %w", err)
|
||||
}
|
||||
if _, err := tx.Exec(ctx, `
|
||||
INSERT INTO render_revision_manifest (revision_id, tenant_id, config_generation, manifest_json)
|
||||
VALUES ($1::uuid, $2::uuid, $3, $4::jsonb)`,
|
||||
revisionID, tenantID, gen, body); err != nil {
|
||||
return fmt.Errorf("repository: insert render manifest: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in new issue
Block a user