RunPeriodicMaintenance и RunCleanup удалены; scheduler политик в StartBackground; deprecated /postgres/cleanup принимает policy_id. Co-authored-by: Cursor <[email protected]>
97 lines
3.3 KiB
Go
97 lines
3.3 KiB
Go
package pgmonitor
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
// CleanupRequest for deprecated POST /postgres/cleanup (use /v1/maintenance/run).
|
|
type CleanupRequest struct {
|
|
PolicyID string `json:"policy_id"`
|
|
Policy string `json:"policy"`
|
|
DryRun bool `json:"dry_run"`
|
|
Limit int `json:"limit"`
|
|
}
|
|
|
|
// InsertMaintenanceAudit records an audit row at job start.
|
|
func InsertMaintenanceAudit(ctx context.Context, pool *pgxpool.Pool, tenantID, actorPrefix, kind, table string, dryRun bool) (string, error) {
|
|
return InsertMaintenanceAuditWithPolicy(ctx, pool, tenantID, actorPrefix, kind, table, "", dryRun)
|
|
}
|
|
|
|
// InsertMaintenanceAuditWithPolicy records an audit row linked to maintenance_policy.
|
|
func InsertMaintenanceAuditWithPolicy(ctx context.Context, pool *pgxpool.Pool, tenantID, actorPrefix, kind, table, policyID string, dryRun bool) (string, error) {
|
|
id := uuid.New().String()
|
|
_, err := pool.Exec(ctx, `
|
|
INSERT INTO postgres_maintenance_audit
|
|
(id, tenant_id, actor_prefix, kind, target_table, policy_id, dry_run, status, created_at)
|
|
VALUES ($1, NULLIF($2,''), NULLIF($3,''), $4, NULLIF($5,''), NULLIF($6,''), $7, 'running', now())`,
|
|
id, tenantID, actorPrefix, kind, table, policyID, dryRun)
|
|
return id, err
|
|
}
|
|
|
|
// FinishMaintenanceAudit updates terminal state.
|
|
func FinishMaintenanceAudit(ctx context.Context, pool *pgxpool.Pool, id, status string, detail map[string]any, errMsg *string) error {
|
|
var detailJSON []byte
|
|
if detail != nil {
|
|
detailJSON, _ = json.Marshal(detail)
|
|
}
|
|
_, err := pool.Exec(ctx, `
|
|
UPDATE postgres_maintenance_audit
|
|
SET status = $2, detail_json = $3::jsonb, error_message = $4,
|
|
finished_at = now(), started_at = COALESCE(started_at, now())
|
|
WHERE id = $1`,
|
|
id, status, string(detailJSON), errMsg)
|
|
return err
|
|
}
|
|
|
|
// ListMaintenanceLogs returns paginated audit rows.
|
|
func ListMaintenanceLogs(ctx context.Context, pool *pgxpool.Pool, cursor string, limit int) ([]MaintenanceLogRow, string, bool, error) {
|
|
limit = clampLimit(limit, 20, 100)
|
|
args := []any{limit + 1}
|
|
q := `
|
|
SELECT id, COALESCE(tenant_id,''), COALESCE(actor_prefix,''), kind,
|
|
COALESCE(target_table,''), dry_run, status,
|
|
detail_json, COALESCE(error_message,''), created_at, started_at, finished_at
|
|
FROM postgres_maintenance_audit`
|
|
if cursor != "" {
|
|
q += ` WHERE created_at < (SELECT created_at FROM postgres_maintenance_audit WHERE id = $2)`
|
|
args = append(args, cursor)
|
|
}
|
|
q += ` ORDER BY created_at DESC LIMIT $1`
|
|
|
|
rows, err := pool.Query(ctx, q, args...)
|
|
if err != nil {
|
|
return nil, "", false, err
|
|
}
|
|
defer rows.Close()
|
|
var out []MaintenanceLogRow
|
|
for rows.Next() {
|
|
var r MaintenanceLogRow
|
|
var detailRaw []byte
|
|
var started, finished *time.Time
|
|
if err := rows.Scan(&r.ID, &r.TenantID, &r.ActorPrefix, &r.Kind, &r.TargetTable,
|
|
&r.DryRun, &r.Status, &detailRaw, &r.Error, &r.CreatedAt, &started, &finished); err != nil {
|
|
return nil, "", false, err
|
|
}
|
|
r.StartedAt = started
|
|
r.FinishedAt = finished
|
|
if len(detailRaw) > 0 {
|
|
_ = json.Unmarshal(detailRaw, &r.Detail)
|
|
}
|
|
out = append(out, r)
|
|
}
|
|
hasMore := len(out) > limit
|
|
if hasMore {
|
|
out = out[:limit]
|
|
}
|
|
next := ""
|
|
if hasMore && len(out) > 0 {
|
|
next = out[len(out)-1].ID
|
|
}
|
|
return out, next, hasMore, rows.Err()
|
|
}
|