fix: enhance publish record deletion logic and add soft delete functionality
Backend CI / Backend (push) Successful in 14m47s
Backend CI / Backend (push) Successful in 14m47s
This commit is contained in:
@@ -425,16 +425,17 @@ func (s *MediaService) DeletePublishRecord(ctx context.Context, recordID int64)
|
|||||||
|
|
||||||
var publishBatchID int64
|
var publishBatchID int64
|
||||||
var articleID int64
|
var articleID int64
|
||||||
var cancelErrorJSON []byte
|
var publishStatus string
|
||||||
cancelErrorJSON, err = marshalOptionalJSON(map[string]any{
|
cancelErrorJSONBytes, err := marshalOptionalJSON(map[string]any{
|
||||||
"reason": "publish_record_deleted",
|
"reason": "publish_record_deleted",
|
||||||
"source": "tenant_web",
|
"source": "tenant_web",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.ErrInternal(50044, "publish_record_delete_payload_failed", "failed to delete publish record")
|
return nil, response.ErrInternal(50044, "publish_record_delete_payload_failed", "failed to delete publish record")
|
||||||
}
|
}
|
||||||
|
cancelErrorJSON := string(cancelErrorJSONBytes)
|
||||||
err = tx.QueryRow(ctx, `
|
err = tx.QueryRow(ctx, `
|
||||||
SELECT pr.publish_batch_id, pr.article_id
|
SELECT pr.publish_batch_id, pr.article_id, pr.status
|
||||||
FROM publish_records pr
|
FROM publish_records pr
|
||||||
JOIN articles a
|
JOIN articles a
|
||||||
ON a.id = pr.article_id
|
ON a.id = pr.article_id
|
||||||
@@ -447,7 +448,7 @@ func (s *MediaService) DeletePublishRecord(ctx context.Context, recordID int64)
|
|||||||
AND pb.initiator_user_id = $3
|
AND pb.initiator_user_id = $3
|
||||||
AND pr.deleted_at IS NULL
|
AND pr.deleted_at IS NULL
|
||||||
FOR UPDATE OF pr
|
FOR UPDATE OF pr
|
||||||
`, recordID, actor.TenantID, actor.UserID).Scan(&publishBatchID, &articleID)
|
`, recordID, actor.TenantID, actor.UserID).Scan(&publishBatchID, &articleID, &publishStatus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, pgx.ErrNoRows) {
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
return nil, response.ErrNotFound(40435, "publish_record_not_found", "publish record not found")
|
return nil, response.ErrNotFound(40435, "publish_record_not_found", "publish record not found")
|
||||||
@@ -468,20 +469,22 @@ func (s *MediaService) DeletePublishRecord(ctx context.Context, recordID int64)
|
|||||||
return nil, response.ErrNotFound(40435, "publish_record_not_found", "publish record not found")
|
return nil, response.ErrNotFound(40435, "publish_record_not_found", "publish record not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := tx.Exec(ctx, `
|
if publishRecordMayHaveQueuedTask(publishStatus) {
|
||||||
UPDATE desktop_tasks
|
if _, err := tx.Exec(ctx, `
|
||||||
SET status = 'aborted',
|
UPDATE desktop_tasks
|
||||||
error = $3,
|
SET status = 'aborted',
|
||||||
active_attempt_id = NULL,
|
error = $3::jsonb,
|
||||||
lease_token_hash = NULL,
|
active_attempt_id = NULL,
|
||||||
lease_expires_at = NULL,
|
lease_token_hash = NULL,
|
||||||
updated_at = NOW()
|
lease_expires_at = NULL,
|
||||||
WHERE tenant_id = $1
|
updated_at = NOW()
|
||||||
AND kind = 'publish'
|
WHERE tenant_id = $1
|
||||||
AND status = 'queued'
|
AND kind = 'publish'
|
||||||
AND payload->>'publish_record_id' = $2
|
AND status = 'queued'
|
||||||
`, actor.TenantID, recordID, cancelErrorJSON); err != nil {
|
AND payload->>'publish_record_id' = $2::text
|
||||||
return nil, response.ErrInternal(50044, "publish_record_delete_cancel_task_failed", "failed to cancel queued publish task before deleting record")
|
`, actor.TenantID, recordID, cancelErrorJSON); err != nil {
|
||||||
|
return nil, response.ErrInternal(50044, "publish_record_delete_cancel_task_failed", "failed to cancel queued publish task before deleting record")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
batchStatus, err := recalculatePublishBatchStatus(ctx, tx, publishBatchID)
|
batchStatus, err := recalculatePublishBatchStatus(ctx, tx, publishBatchID)
|
||||||
@@ -532,6 +535,15 @@ func publishPlatformRequiresCover(platformID string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func publishRecordMayHaveQueuedTask(status string) bool {
|
||||||
|
switch strings.TrimSpace(status) {
|
||||||
|
case "queued", "publishing", "pending", "running":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func pointerStringValue(value *string) string {
|
func pointerStringValue(value *string) string {
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ func cancelQueuedPublishTasksForUnavailableArticle(ctx context.Context, tx pgx.T
|
|||||||
if tx == nil || tenantID <= 0 || articleID <= 0 {
|
if tx == nil || tenantID <= 0 || articleID <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
errorJSON, err := marshalOptionalJSON(map[string]any{
|
errorJSONBytes, err := marshalOptionalJSON(map[string]any{
|
||||||
"code": "article_unavailable",
|
"code": "article_unavailable",
|
||||||
"message": "article is unavailable before publishing",
|
"message": "article is unavailable before publishing",
|
||||||
"source": "article_unavailable_cleanup",
|
"source": "article_unavailable_cleanup",
|
||||||
@@ -123,6 +123,7 @@ func cancelQueuedPublishTasksForUnavailableArticle(ctx context.Context, tx pgx.T
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return response.ErrInternal(50120, "publish_task_cancel_payload_failed", "failed to encode publish task cancellation payload")
|
return response.ErrInternal(50120, "publish_task_cancel_payload_failed", "failed to encode publish task cancellation payload")
|
||||||
}
|
}
|
||||||
|
errorJSON := string(errorJSONBytes)
|
||||||
|
|
||||||
if _, err := tx.Exec(ctx, `
|
if _, err := tx.Exec(ctx, `
|
||||||
WITH affected_records AS (
|
WITH affected_records AS (
|
||||||
@@ -154,7 +155,7 @@ func cancelQueuedPublishTasksForUnavailableArticle(ctx context.Context, tx pgx.T
|
|||||||
updated_tasks AS (
|
updated_tasks AS (
|
||||||
UPDATE desktop_tasks dt
|
UPDATE desktop_tasks dt
|
||||||
SET status = 'aborted',
|
SET status = 'aborted',
|
||||||
error = $3,
|
error = $3::jsonb,
|
||||||
active_attempt_id = NULL,
|
active_attempt_id = NULL,
|
||||||
lease_token_hash = NULL,
|
lease_token_hash = NULL,
|
||||||
lease_expires_at = NULL,
|
lease_expires_at = NULL,
|
||||||
@@ -280,7 +281,7 @@ func cancelQueuedPublishTasksForDesktopAccountUnbind(
|
|||||||
if tx == nil || tenantID <= 0 || workspaceID <= 0 || accountID == uuid.Nil {
|
if tx == nil || tenantID <= 0 || workspaceID <= 0 || accountID == uuid.Nil {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
errorJSON, err := marshalOptionalJSON(map[string]any{
|
errorJSONBytes, err := marshalOptionalJSON(map[string]any{
|
||||||
"code": "desktop_account_unbound",
|
"code": "desktop_account_unbound",
|
||||||
"message": "desktop account was unbound before publishing",
|
"message": "desktop account was unbound before publishing",
|
||||||
"source": "desktop_account_unbind",
|
"source": "desktop_account_unbind",
|
||||||
@@ -288,6 +289,7 @@ func cancelQueuedPublishTasksForDesktopAccountUnbind(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, response.ErrInternal(50120, "publish_task_cancel_payload_failed", "failed to encode publish task cancellation payload")
|
return 0, response.ErrInternal(50120, "publish_task_cancel_payload_failed", "failed to encode publish task cancellation payload")
|
||||||
}
|
}
|
||||||
|
errorJSON := string(errorJSONBytes)
|
||||||
|
|
||||||
rows, err := tx.Query(ctx, `
|
rows, err := tx.Query(ctx, `
|
||||||
SELECT DISTINCT pr.id, pr.publish_batch_id, pr.article_id
|
SELECT DISTINCT pr.id, pr.publish_batch_id, pr.article_id
|
||||||
@@ -354,7 +356,7 @@ func cancelQueuedPublishTasksForDesktopAccountUnbind(
|
|||||||
tag, err := tx.Exec(ctx, `
|
tag, err := tx.Exec(ctx, `
|
||||||
UPDATE desktop_tasks dt
|
UPDATE desktop_tasks dt
|
||||||
SET status = 'aborted',
|
SET status = 'aborted',
|
||||||
error = $4,
|
error = $4::jsonb,
|
||||||
active_attempt_id = NULL,
|
active_attempt_id = NULL,
|
||||||
lease_token_hash = NULL,
|
lease_token_hash = NULL,
|
||||||
lease_expires_at = NULL,
|
lease_expires_at = NULL,
|
||||||
|
|||||||
@@ -1,9 +1,2 @@
|
|||||||
DROP INDEX CONCURRENTLY IF EXISTS idx_publish_records_visible_status;
|
|
||||||
|
|
||||||
DROP INDEX CONCURRENTLY IF EXISTS idx_publish_records_article_account_active;
|
|
||||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_publish_records_article_account_active
|
|
||||||
ON publish_records (tenant_id, article_id, platform_account_id, updated_at DESC, id DESC)
|
|
||||||
WHERE status IN ('queued', 'publishing', 'success');
|
|
||||||
|
|
||||||
ALTER TABLE publish_records
|
ALTER TABLE publish_records
|
||||||
DROP COLUMN IF EXISTS deleted_at;
|
DROP COLUMN IF EXISTS deleted_at;
|
||||||
|
|||||||
@@ -1,12 +1,2 @@
|
|||||||
ALTER TABLE publish_records
|
ALTER TABLE publish_records
|
||||||
ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ;
|
ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ;
|
||||||
|
|
||||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_publish_records_visible_status
|
|
||||||
ON publish_records (tenant_id, status, created_at DESC, id DESC)
|
|
||||||
WHERE deleted_at IS NULL;
|
|
||||||
|
|
||||||
DROP INDEX CONCURRENTLY IF EXISTS idx_publish_records_article_account_active;
|
|
||||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_publish_records_article_account_active
|
|
||||||
ON publish_records (tenant_id, article_id, platform_account_id, updated_at DESC, id DESC)
|
|
||||||
WHERE status IN ('queued', 'publishing', 'success')
|
|
||||||
AND deleted_at IS NULL;
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX CONCURRENTLY IF EXISTS idx_publish_records_visible_status;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_publish_records_visible_status
|
||||||
|
ON publish_records (tenant_id, status, created_at DESC, id DESC)
|
||||||
|
WHERE deleted_at IS NULL;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_publish_records_article_account_active
|
||||||
|
ON publish_records (tenant_id, article_id, platform_account_id, updated_at DESC, id DESC)
|
||||||
|
WHERE status IN ('queued', 'publishing', 'success');
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX CONCURRENTLY IF EXISTS idx_publish_records_article_account_active;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX CONCURRENTLY IF EXISTS idx_publish_records_article_account_active;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_publish_records_article_account_active
|
||||||
|
ON publish_records (tenant_id, article_id, platform_account_id, updated_at DESC, id DESC)
|
||||||
|
WHERE status IN ('queued', 'publishing', 'success')
|
||||||
|
AND deleted_at IS NULL;
|
||||||
Reference in New Issue
Block a user