Fix false stall detection for multi-article chained generation

The frontend status poller measured elapsed time from `started` (set once
at the beginning of the run) and declared a stall at 300s.  Three articles
take ~6 minutes total, so the poller always false-alarmed on article 3.

Now every stage broadcast writes `last_updated` into the transient, and
the stall check compares idle time since the last update — not since the
run started.  This lets N-article runs complete without false timeout as
long as each individual article finishes within 5 minutes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
peptiderepo
2026-04-19 03:40:05 +07:00
parent ef40ce91d4
commit cc6979b085
3 changed files with 19 additions and 16 deletions

View File

@@ -105,9 +105,10 @@ class PRAutoBlogger_Executor {
// Write initial "running" status for the frontend to poll.
set_transient( self::STATUS_TRANSIENT, [
'status' => 'running',
'stage' => __( 'Starting generation...', 'prautoblogger' ),
'started' => time(),
'status' => 'running',
'stage' => __( 'Starting generation...', 'prautoblogger' ),
'started' => time(),
'last_updated' => time(),
], self::STATUS_TTL );
// Schedule immediate one-shot cron event. WordPress will fire this
@@ -190,11 +191,7 @@ class PRAutoBlogger_Executor {
}
}
/**
* Cron handler: process the next queued article in its own PHP process.
*
* Chained by Pipeline_Runner — each article gets its own execution time.
*/
/** Cron handler: process next queued article. Chained by Pipeline_Runner. */
public function on_process_article_queue(): void {
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
@ignore_user_abort( true );
@@ -249,8 +246,10 @@ class PRAutoBlogger_Executor {
}
}
// After 5 min with no progress, declare failure.
if ( $elapsed > 300 ) {
// Stall = 5 min since last stage update (not since start).
$last_activity = $status['last_updated'] ?? $status['started'] ?? 0;
$idle_seconds = time() - $last_activity;
if ( $idle_seconds > 300 ) {
$this->abort_orphaned_run( __( 'Generation stalled. Check Activity Log.', 'prautoblogger' ) );
return;
}
@@ -275,7 +274,8 @@ class PRAutoBlogger_Executor {
private function update_generation_stage( string $stage ): void {
$current = get_transient( self::STATUS_TRANSIENT );
if ( is_array( $current ) ) {
$current['stage'] = $stage;
$current['stage'] = $stage;
$current['last_updated'] = time();
set_transient( self::STATUS_TRANSIENT, $current, self::STATUS_TTL );
}
}

View File

@@ -137,7 +137,8 @@ class PRAutoBlogger_Article_Worker {
$transient_key = 'prautoblogger_generation_status';
$current = get_transient( $transient_key );
if ( is_array( $current ) && 'running' === ( $current['status'] ?? '' ) ) {
$current['stage'] = $stage;
$current['stage'] = $stage;
$current['last_updated'] = time();
set_transient( $transient_key, $current, 600 );
}
}

View File

@@ -213,9 +213,10 @@ class PRAutoBlogger_Pipeline_Runner {
$current = get_transient( 'prautoblogger_generation_status' );
set_transient( 'prautoblogger_generation_status', [
'status' => 'running',
'stage' => sprintf( __( 'Generating article %1$d of %2$d…', 'prautoblogger' ), $done + 1, $total ),
'started' => is_array( $current ) ? ( $current['started'] ?? time() ) : time(),
'status' => 'running',
'stage' => sprintf( __( 'Generating article %1$d of %2$d…', 'prautoblogger' ), $done + 1, $total ),
'started' => is_array( $current ) ? ( $current['started'] ?? time() ) : time(),
'last_updated' => time(),
], 600 );
}
@@ -256,7 +257,8 @@ class PRAutoBlogger_Pipeline_Runner {
$key = 'prautoblogger_generation_status';
$current = get_transient( $key );
if ( is_array( $current ) && 'running' === ( $current['status'] ?? '' ) ) {
$current['stage'] = $stage;
$current['stage'] = $stage;
$current['last_updated'] = time();
set_transient( $key, $current, 600 );
}
}