How ACE-Step UI Polls for Generation Job Status Updates

ACE-Step UI maintains a client-side Map of active jobs and executes a setInterval loop every 2 seconds to query GET /api/generate/status/:jobId, updating temporary placeholders until the job reaches succeeded or failed status, with automatic cleanup and 10-minute timeout protection.

When users initiate AI music generation in the fspecii/ace-step-ui repository, the front-end must track asynchronous back-end jobs without freezing the interface. The application implements a self-healing polling mechanism that creates temporary song placeholders, repeatedly queries the server for status updates, and synchronizes progress data in real-time.

The Polling Architecture

Tracking Active Jobs with activeJobsRef

The core state management relies on a mutable React ref that persists across renders without triggering re-renders. In src/App.tsx (lines 39-45), the UI initializes a Map structure:

const activeJobsRef = useRef<Map<string, {
  tempId: string;
  pollInterval: ReturnType<typeof setInterval>;
}>>(new Map());

This Map stores the correlation between server-side jobId values and client-side temporary song IDs, along with their active setInterval handles for later cleanup.

Initialization Flow

When a user submits a generation request, the UI immediately creates a temporary placeholder song to provide immediate visual feedback. After generateApi.startGeneration returns a jobId from the back-end (App.tsx, lines 557-564), the application invokes beginPollingJob(jobId, tempId) to commence status monitoring.

Inside the Polling Loop (beginPollingJob)

The beginPollingJob function (App.tsx, lines 99-143) establishes a 2-second polling interval that executes the following sequence:

  • Status Retrieval: Calls generateApi.getStatus(jobId, token), which wraps the authenticated GET /api/generate/status/:jobId endpoint (services/api.ts, lines 37-38).
  • Progress Normalization: Converts the server-reported progress value to a 0-1 range for the UI progress bar.
  • State Synchronization: Updates the temporary song object in React state with current progress, stage, and queuePosition values.
  • Terminal State Handling:
    • Success: When status equals succeeded, the interval clears via clearInterval, the placeholder removes from state, and the real song list refreshes to include the completed generation.
    • Failure: When status equals failed, the interval clears, the placeholder removes, and an error toast displays via the Toast component.

Resilience Mechanisms

Timeout Protection

To prevent infinite polling of stalled jobs, the implementation enforces a 10-minute timeout (App.tsx, lines 47-53). If a job exceeds 600 seconds without reaching a terminal state, the UI aborts the poll, removes the temporary placeholder, and displays a "generation timed out" notification.

Session Recovery on Reload

If the user refreshes the browser during active generation, the UI does not lose track of in-progress work. During initialization (App.tsx, lines 71-84), the application queries generateApi.getHistory to retrieve the server's generation history. For any jobs still in non-terminal states, it reconstructs temporary placeholder songs and re-invokes beginPollingJob to resume the 2-second polling cycle.

Cleanup and Memory Management

The cleanupJob helper (App.tsx, lines 26-43) ensures proper resource disposal by clearing the setInterval handle, deleting the entry from activeJobsRef, and updating UI counters. This prevents memory leaks and interval duplication when components unmount or jobs complete.

Implementation Example

The following pattern demonstrates how a component initiates generation and delegates status monitoring to the polling system:

import { generateApi } from './services/api';

const onGenerate = async (params: GenerationParams) => {
  // Create temporary placeholder for immediate UI feedback
  const tempId = `temp_${Date.now()}`;
  setSongs(prev => [
    { id: tempId, title: 'Generating…', isGenerating: true, progress: 0 }, 
    ...prev
  ]);

  // Initiate back-end job
  const job = await generateApi.startGeneration(params, token);
  
  // Begin 2-second interval polling
  beginPollingJob(job.jobId, tempId);
};

Summary

  • ACE-Step UI stores active job metadata in activeJobsRef, a React ref containing a Map that associates server jobId values with temporary UI IDs and interval handles.
  • The beginPollingJob function in src/App.tsx creates a 2-second setInterval that queries GET /api/generate/status/:jobId via the generateApi.getStatus wrapper.
  • Progress updates normalize server responses to update placeholder songs with real-time progress, stage, and queuePosition data.
  • Terminal states (succeeded or failed) trigger automatic cleanup, placeholder removal, and appropriate user feedback via toast notifications.
  • A 10-minute timeout safeguard prevents indefinite polling of stalled jobs.
  • On application reload, the UI resumes polling for any active jobs discovered in the generation history via generateApi.getHistory.

Frequently Asked Questions

What endpoint does ACE-Step UI poll for generation status?

The UI polls GET /api/generate/status/:jobId every 2 seconds. This endpoint is accessed through the generateApi.getStatus method defined in src/services/api.ts (lines 37-38), which handles authentication token injection and response normalization.

How does ACE-Step UI prevent memory leaks when polling?

The application stores setInterval handles in a React ref-based Map called activeJobsRef. When a job completes, fails, or times out, the cleanupJob function (App.tsx, lines 26-43) clears the interval using clearInterval and deletes the Map entry, ensuring no orphaned timers persist after component unmount or job completion.

What happens if I refresh the page during generation?

ACE-Step UI implements session recovery logic in src/App.tsx (lines 71-84). On mount, it fetches the generation history via generateApi.getHistory and identifies any jobs still in progress. For each active job, it reconstructs the temporary placeholder and calls beginPollingJob to resume the 2-second polling cycle without user intervention.

How long will ACE-Step UI wait for a generation to complete?

The polling mechanism includes a 10-minute timeout guard (App.tsx, lines 47-53). If a job fails to reach succeeded or failed status within 600 seconds, the UI automatically aborts polling, removes the temporary song placeholder, and displays a timeout error toast to the user.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →