feat: implement brand asset cleanup event handling and reconciliation logic
Backend CI / Backend (push) Failing after 6m54s
Backend CI / Backend (push) Failing after 6m54s
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
)
|
||||
|
||||
const BrandAssetCleanupNotifyChannel = "brand_asset_cleanup_events"
|
||||
|
||||
type brandAssetCleanupEventQuerier interface {
|
||||
Exec(context.Context, string, ...any) (pgconn.CommandTag, error)
|
||||
QueryRow(context.Context, string, ...any) pgx.Row
|
||||
}
|
||||
|
||||
func EnqueueBrandAssetCleanupEvent(ctx context.Context, q brandAssetCleanupEventQuerier, tenantID, brandID int64) (int64, error) {
|
||||
var eventID int64
|
||||
err := q.QueryRow(ctx, `
|
||||
INSERT INTO brand_asset_cleanup_events (tenant_id, brand_id, status, next_attempt_at, last_error, processed_at)
|
||||
VALUES ($1, $2, 'pending', NOW(), NULL, NULL)
|
||||
ON CONFLICT (tenant_id, brand_id) WHERE status IN ('pending', 'processing', 'failed') DO UPDATE
|
||||
SET status = CASE
|
||||
WHEN brand_asset_cleanup_events.status = 'processing' THEN brand_asset_cleanup_events.status
|
||||
ELSE 'pending'
|
||||
END,
|
||||
next_attempt_at = CASE
|
||||
WHEN brand_asset_cleanup_events.status = 'processing' THEN brand_asset_cleanup_events.next_attempt_at
|
||||
ELSE NOW()
|
||||
END,
|
||||
last_error = CASE
|
||||
WHEN brand_asset_cleanup_events.status = 'processing' THEN brand_asset_cleanup_events.last_error
|
||||
ELSE NULL
|
||||
END,
|
||||
processed_at = NULL,
|
||||
updated_at = NOW()
|
||||
RETURNING id
|
||||
`, tenantID, brandID).Scan(&eventID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return eventID, nil
|
||||
}
|
||||
|
||||
func NotifyBrandAssetCleanup(ctx context.Context, q brandAssetCleanupEventQuerier) error {
|
||||
_, err := q.Exec(ctx, `
|
||||
SELECT pg_notify($1, '')
|
||||
`, BrandAssetCleanupNotifyChannel)
|
||||
return err
|
||||
}
|
||||
@@ -309,6 +309,13 @@ func (s *BrandService) Delete(ctx context.Context, id int64) error {
|
||||
_, _ = tx.Exec(ctx, `UPDATE brand_questions SET deleted_at = NOW(), updated_at = NOW() WHERE brand_id = $1 AND tenant_id = $2 AND deleted_at IS NULL`, id, actor.TenantID)
|
||||
_, _ = tx.Exec(ctx, `UPDATE competitors SET deleted_at = NOW(), updated_at = NOW() WHERE brand_id = $1 AND tenant_id = $2 AND deleted_at IS NULL`, id, actor.TenantID)
|
||||
|
||||
if _, err := EnqueueBrandAssetCleanupEvent(ctx, tx, actor.TenantID, id); err != nil {
|
||||
return response.ErrInternal(50010, "delete_failed", "failed to enqueue brand cleanup event")
|
||||
}
|
||||
if err := NotifyBrandAssetCleanup(ctx, tx); err != nil {
|
||||
return response.ErrInternal(50010, "delete_failed", "failed to notify brand cleanup")
|
||||
}
|
||||
|
||||
afterJSON, _ := json.Marshal(map[string]interface{}{"id": id, "status": "deleting", "cleanup": "background"})
|
||||
if err := tx.Commit(ctx); err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user