Workflows createBatch: 100 instances, one per Sume job?

Cloudflare Workflows now creates up to 100 instances per call. Why a 100-job Sume wave fits only on Scale, and why to pass your own instance IDs.

4 min readSume
All posts

Yes, you can start one Cloudflare Workflow per Sume job with the new createBatch() call, but give every instance its own ID and do not submit 100 paid jobs at once unless your plan accepts 120. Sume admits only as many paid jobs as concurrency + queue capacity, and on every plan except Scale that is fewer than 100.

Cloudflare's changelog entry dated 2026-10-08 (read 2026-10-10) says createBatch() can create "up to 100 Workflow instances in one call". It has two forms, and the form you pick decides whether you can join an instance back to a Sume job.

What the two createBatch forms do

The changelog describes a count form and a list form. In the count form you pass a count, and every instance gets identical configuration and an auto-generated ID. In the list form you pass an instances array, and each entry carries its own ID and its own parameters. The response has a created list and an errors array that explains failures.

For Sume work the list form is the one to use. A Sume submit returns a job id (request_id, shaped like job_...) in the first response in every communication mode. If that id becomes the Workflow instance ID, a later job.completed webhook can be routed to the right instance by id alone. With auto-generated IDs you would need a side table that maps instance to job.

Cloudflare changelog 2026-10-08, read 2026-10-10, mapped to a Sume wave
createBatch formInstance IDPer-instance paramsJoin back to a Sume job
countAuto-generatedIdentical for allNeeds your own lookup table
instances listYou choose, one per entryDifferent per entryUse the Sume job id or your own idempotency key as the ID

Why 100 instances is not 100 accepted Sume jobs

The Workflows limit and the Sume limit are separate. Generation admission says Sume separates concurrency (jobs in processing), queue capacity (accepted, not yet started), submit rate limits and balance. When both concurrency and queue are full, a new paid submit fails with 429 queue_full.

The docs give the default numbers by plan. Accepted job capacity is concurrency_limit + queued_jobs_limit, which is the most paid jobs that can be processing or queued at the same time. The docs also say to prefer the effective generation_limits field over the static table, so read it before you size a wave.

Sume generation admission defaults (docs.sume.com, read 2026-10-10)
PlanProcessingQueue capacityAccepted at onceRoom for a 100-instance batch?
Free156No: 94 would be refused
Pro42024No: 76 would be refused
Startup84048No: 52 would be refused
Scale20100120Yes, with 20 to spare

A safer wave pattern

Treat the batch size as a cap, not a target. Size each createBatch() to the accepted capacity you read from generation_limits, minus the jobs already running. Each instance should submit its Sume job with an Idempotency-Key derived from the instance ID. The docs say a retry with the same key returns the original job and does not bill a second one, so a replayed Workflow step is safe.

Write budgets matter too. Authentication gives writes per minute by plan: 120 on Free, 300 on Pro, 600 on Startup and 1200 on Scale. A hundred submits are a hundred writes, and polls are reads with a separate, larger budget. A 429 rate_limited carries retry-after, and the docs tell you to wait that long.

  • Pass instances with your own IDs, one per Sume job or per input row.
  • Read generation_limits first and cap the batch at free accepted capacity.
  • Send mode: "webhook" and keep status_url polls as a backup.
  • On 429 queue_full, back off and retry with the same idempotency key.

Handling errors and callbacks

The errors array in the createBatch response tells you which instances did not start. Retry only those entries, and keep the same IDs so a retry cannot create a duplicate instance for the same Sume job.

On the Sume side, Webhooks says delivery is up to 10 attempts, 30 seconds apart by default, with a 10 second timeout per attempt. Return a 2xx only after you store the event, and use job_id as the idempotency key. After the attempts run out the job still reached its real state, so keep the status poll as the recovery path. Redeliver re-sends a real terminal event with a fresh timestamp and signature.

Sources

Related posts

More in Integrations

All Integrations posts

Written by Sume