feat(publish-dedup): reject duplicate publish jobs and expose target task ids
Build a per-target dedup_key (tenant/workspace/article/platform/account) on publish job creation, take an xact advisory lock on the keys, look up already-active publish_records via the payload index, and skip creating duplicate desktop_tasks. Surface created vs existing task ids on CreatePublishJobResponse (and shared-types) so callers can tell the difference, return `desktop_publish_duplicate` on unique-constraint races, and expose desktop_account_id on PublishRecordResponse so the modal can disable already-published accounts. Make the compliance ack consumer accept a nullable job id since the dedup short-circuit no longer creates one. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,7 @@ type PublishRecordResponse struct {
|
||||
PublishBatchID int64 `json:"publish_batch_id"`
|
||||
ArticleID int64 `json:"article_id"`
|
||||
PlatformAccountID int64 `json:"platform_account_id"`
|
||||
DesktopAccountID *string `json:"desktop_account_id"`
|
||||
PlatformID string `json:"platform_id"`
|
||||
PlatformName string `json:"platform_name"`
|
||||
PlatformNickname string `json:"platform_nickname"`
|
||||
@@ -97,7 +98,7 @@ func (s *MediaService) ListArticlePublishRecords(ctx context.Context, articleID
|
||||
|
||||
func (s *MediaService) listArticlePublishRecords(ctx context.Context, tenantID, brandID, articleID int64) ([]PublishRecordResponse, error) {
|
||||
rows, err := s.pool.Query(ctx, `
|
||||
SELECT pr.id, pr.publish_batch_id, pr.article_id, pr.platform_account_id, pr.platform_id,
|
||||
SELECT pr.id, pr.publish_batch_id, pr.article_id, pr.platform_account_id, pa.desktop_id::text, pr.platform_id,
|
||||
mp.name, pa.nickname, pr.status, pr.external_article_id, pr.external_article_url,
|
||||
pr.external_manage_url, pr.published_at, pr.error_message, pr.created_at, pr.updated_at
|
||||
FROM publish_records pr
|
||||
@@ -115,11 +116,13 @@ func (s *MediaService) listArticlePublishRecords(ctx context.Context, tenantID,
|
||||
items := make([]PublishRecordResponse, 0)
|
||||
for rows.Next() {
|
||||
var item PublishRecordResponse
|
||||
var desktopAccountID string
|
||||
if err := rows.Scan(
|
||||
&item.ID,
|
||||
&item.PublishBatchID,
|
||||
&item.ArticleID,
|
||||
&item.PlatformAccountID,
|
||||
&desktopAccountID,
|
||||
&item.PlatformID,
|
||||
&item.PlatformName,
|
||||
&item.PlatformNickname,
|
||||
@@ -134,6 +137,9 @@ func (s *MediaService) listArticlePublishRecords(ctx context.Context, tenantID,
|
||||
); err != nil {
|
||||
return nil, response.ErrInternal(50043, "publish_record_scan_failed", err.Error())
|
||||
}
|
||||
if strings.TrimSpace(desktopAccountID) != "" {
|
||||
item.DesktopAccountID = &desktopAccountID
|
||||
}
|
||||
normalizePublishRecordForResponse(&item)
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user