Environment
vercel==0.5.8
- Python 3.12 (Vercel Lambda runtime)
The bug
The workflow runtime computes the delay for a vercel.workflow.sleep wakeup as:
# src/vercel/_internal/workflow/runtime.py:441
seconds = (sus.resume_at - now).total_seconds()
That's a float. worlds/vercel.py:237 clamps it (also float math) and passes it through unchanged to vqs_client.send_async(... delay_seconds=...). The Vercel queue server then rejects:
{"error":"Invalid Vqs-Delay-Seconds. Must be an integer between 0 and 86400 seconds (cannot exceed retention time)"}
So the very first sleep() wakeup queue-send 400s.
Repro
from vercel.workflow import sleep
from vercel._internal.workflow import Workflows
wf = Workflows()
@wf.step
async def noop_step(*, payload: dict) -> None:
return
@wf.workflow
async def my_workflow(*, payload: dict) -> None:
await noop_step(payload=payload)
await sleep("60 seconds") # → world.queue(..., delay_seconds=60.0) → 400
The chain self-heals eventually (after resume_at is in the past, min_timeout_seconds flips negative and no delay_seconds is sent), but each cycle takes ~5 minutes of queue redeliveries and floods the worker logs with 500s/400s. Compounded by #(other-issue-id, the DuplicateIdempotencyKeyError AttributeError) which masks the original BadRequestError.
Suggested fix
int(delay_seconds) (or math.ceil if you want to err on the side of "wake no earlier than requested") before passing it to the queue client. Fractional seconds are meaningless at the queue's per-second granularity.
Environment
vercel==0.5.8The bug
The workflow runtime computes the delay for a
vercel.workflow.sleepwakeup as:That's a
float.worlds/vercel.py:237clamps it (also float math) and passes it through unchanged tovqs_client.send_async(... delay_seconds=...). The Vercel queue server then rejects:So the very first
sleep()wakeup queue-send 400s.Repro
The chain self-heals eventually (after
resume_atis in the past,min_timeout_secondsflips negative and nodelay_secondsis sent), but each cycle takes ~5 minutes of queue redeliveries and floods the worker logs with 500s/400s. Compounded by #(other-issue-id, theDuplicateIdempotencyKeyErrorAttributeError) which masks the originalBadRequestError.Suggested fix
int(delay_seconds)(ormath.ceilif you want to err on the side of "wake no earlier than requested") before passing it to the queue client. Fractional seconds are meaningless at the queue's per-second granularity.