From 00cfb39253819ea1b341f7879e0515afe308aaa2 Mon Sep 17 00:00:00 2001 From: peptiderepo Date: Sun, 19 Apr 2026 11:53:34 +0700 Subject: [PATCH] Fix race condition causing duplicate article generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The status poller's orphan-recovery logic re-scheduled cron events for articles already being generated. During the ~90s generation window, the queue option in the DB still contained the in-progress idea because the process only deleted/updated it AFTER generation completed. Fix: persist the consumed queue to the DB BEFORE starting generation. When the poller checks get_option(), it now sees either an empty queue (for the last article) or a queue without the current idea, so orphan recovery cannot duplicate work. Root cause: process_next_queued_article() did array_shift on a local variable but left the DB unchanged until after the slow LLM+image generation finished. The poller saw the stale DB state, assumed the cron event had died, and re-scheduled it — producing a 4th post from 3 ideas on every run. Co-Authored-By: Claude Opus 4.6 --- includes/core/class-pipeline-runner.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/includes/core/class-pipeline-runner.php b/includes/core/class-pipeline-runner.php index 6d19bd6..d2fbd25 100755 --- a/includes/core/class-pipeline-runner.php +++ b/includes/core/class-pipeline-runner.php @@ -110,6 +110,16 @@ class PRAutoBlogger_Pipeline_Runner { return; } + // Persist the consumed queue BEFORE generating so the status poller + // cannot re-schedule a cron event for the same idea. Without this, + // the DB still holds the old queue during the ~90s generation window, + // and the poller's orphan-recovery logic duplicates the last article. + if ( ! empty( $queue['ideas'] ) ) { + update_option( self::QUEUE_KEY, $queue, false ); + } else { + delete_option( self::QUEUE_KEY ); + } + $worker = new PRAutoBlogger_Article_Worker( $cost_tracker ); $article_result = $worker->generate( $idea );