Add common third party reenrich and stats CLIs
Add `proboctl common-third-party reenrich` to re-arm the async enrichment worker for selected catalog rows, and `stats` to summarize the catalog by enrichment state and last run status. Rows are selected verbatim via --id/--slug or across the catalog via --category/--keyword/--state/--status, gated by --dry-run and --yes. Extend `list` with --state/--status filters and STATE/STATUS columns, and `show` with enrichment state, attempts, last run status, error, per-field provenance, and discovered domains. Back these with CommonThirdPartyFilter state/status/IDs filters plus CommonThirdParties.LoadAllIDs and RequestEnrichmentByIDs. The latter stamps enrichment_requested_at and resets the attempt counter while preserving the existing payload, so the worker merge keeps curated and human-edited provenance. Also simplify exactLabelMatch to use slices.Contains. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
@@ -655,6 +655,42 @@ LIMIT 20
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadAllIDs returns the IDs of every common third party matching the
|
||||
// filter, ignoring pagination. It is the selection primitive behind bulk
|
||||
// operator actions such as re-arming enrichment across a filtered set.
|
||||
func (t *CommonThirdParties) LoadAllIDs(
|
||||
ctx context.Context,
|
||||
conn pg.Querier,
|
||||
filter *CommonThirdPartyFilter,
|
||||
) ([]gid.GID, error) {
|
||||
q := `
|
||||
SELECT
|
||||
id
|
||||
FROM
|
||||
common_third_parties
|
||||
WHERE
|
||||
%s
|
||||
ORDER BY name ASC
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, filter.SQLFragment())
|
||||
|
||||
args := pgx.StrictNamedArgs{}
|
||||
maps.Copy(args, filter.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot query common third party ids: %w", err)
|
||||
}
|
||||
|
||||
ids, err := pgx.CollectRows(rows, pgx.RowTo[gid.GID])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot collect common third party ids: %w", err)
|
||||
}
|
||||
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
func (t CommonThirdParty) UpdateLogoFileID(
|
||||
ctx context.Context,
|
||||
conn pg.Tx,
|
||||
@@ -1003,3 +1039,40 @@ WHERE
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RequestEnrichmentByIDs re-arms enrichment on the given common third
|
||||
// parties by stamping enrichment_requested_at, which is the only column
|
||||
// the enrichment worker claims on. It resets enrichment_attempts to 0 so
|
||||
// the row gets a fresh retry budget: the claim path bumps the counter on
|
||||
// every run, and without a reset a row near the max-attempts ceiling
|
||||
// would not be re-armed by stale recovery if a re-run crashed. The
|
||||
// enrichment payload is left in place so the worker's merge keeps prior
|
||||
// per-field provenance (it only overwrites fields it owns, never curated
|
||||
// seed data or human edits). Already-enriched rows are re-processed too.
|
||||
// Returns the number of rows re-queued.
|
||||
func (t *CommonThirdParties) RequestEnrichmentByIDs(
|
||||
ctx context.Context,
|
||||
tx pg.Tx,
|
||||
ids []gid.GID,
|
||||
) (int64, error) {
|
||||
q := `
|
||||
UPDATE common_third_parties
|
||||
SET
|
||||
enrichment_requested_at = NOW(),
|
||||
enrichment_attempts = 0,
|
||||
updated_at = NOW()
|
||||
WHERE
|
||||
id = ANY(@ids)
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"ids": ids,
|
||||
}
|
||||
|
||||
result, err := tx.Exec(ctx, q, args)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("cannot request common third party enrichment: %w", err)
|
||||
}
|
||||
|
||||
return result.RowsAffected(), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user