<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: zhenyu xu</title>
    <description>The latest articles on DEV Community by zhenyu xu (@zhenyu_xu_b378d8d11d18138).</description>
    <link>https://dev.to/zhenyu_xu_b378d8d11d18138</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4137979%2F2021eca3-2cad-4a76-9b19-ed6ac7e2387c.png</url>
      <title>DEV Community: zhenyu xu</title>
      <link>https://dev.to/zhenyu_xu_b378d8d11d18138</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zhenyu_xu_b378d8d11d18138"/>
    <language>en</language>
    <item>
      <title>A callback-first recovery pattern for AI video jobs on Vercel</title>
      <dc:creator>zhenyu xu</dc:creator>
      <pubDate>Thu, 01 Oct 2026 12:15:42 +0000</pubDate>
      <link>https://dev.to/zhenyu_xu_b378d8d11d18138/a-callback-first-recovery-pattern-for-ai-video-jobs-on-vercel-2efo</link>
      <guid>https://dev.to/zhenyu_xu_b378d8d11d18138/a-callback-first-recovery-pattern-for-ai-video-jobs-on-vercel-2efo</guid>
      <description>&lt;p&gt;An AI video job should keep running when the user closes the tab. That makes the browser a useful progress display, but a poor owner of the job lifecycle.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://h3-max.me/" rel="noopener noreferrer"&gt;H3 Max&lt;/a&gt;, the video tool I operate, we use a callback-first flow with a delayed recovery check. This is a short implementation note about that design, not a benchmark or a claim that it eliminates background costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate completion from recovery
&lt;/h2&gt;

&lt;p&gt;The normal path lets the model provider's callback save the result. The callback does not create a Workflow just to save a completed video. If a recovery Workflow already exists, the callback can wake it.&lt;/p&gt;

&lt;p&gt;When a job is created, a delayed queue message is also registered with a 60-second delay. That message carries a job ID. When delivered, the consumer reads the current database row rather than assuming the original work still needs attention.&lt;/p&gt;

&lt;p&gt;The consumer returns immediately if the job has been deleted or has reached a terminal state. If the next check is not due, or another worker still holds a lease, it defers the check. Only unresolved, eligible work is handed to a recovery Workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the delay does — and does not — mean
&lt;/h2&gt;

&lt;p&gt;Sixty seconds is an initial recovery checkpoint, not a promise that every model call finishes within a minute. The consumer may defer again based on the job's current state. The queue still incurs work even when the callback succeeds first; what it avoids is starting a recovery Workflow for every successful job.&lt;/p&gt;

&lt;p&gt;This also makes failure handling explicit. A failed Workflow handoff throws so the queue can redeliver the message. A duplicate delivery must check the current state again. Provider completion, database persistence and UI progress are separate concerns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checks worth keeping
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A callback completes the job before the delayed message arrives.&lt;/li&gt;
&lt;li&gt;The callback never arrives, so recovery must take over.&lt;/li&gt;
&lt;li&gt;A message is delivered more than once.&lt;/li&gt;
&lt;li&gt;A job is deleted while background work is pending.&lt;/li&gt;
&lt;li&gt;The Workflow handoff fails temporarily.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This pattern trades constant polling for an event-driven normal path plus a durable recovery path. Its cost depends on callback reliability, job duration and retry behavior, so I would measure those before choosing a delay for a different application.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I operate H3 Max. This article was prepared with AI assistance using the project's current implementation.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>backend</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
