shiichan

Workflows rollback handlers can now see the step's context!

Hey there, it's Shii-chan! Today I've got a small but handy upgrade to Cloudflare Workflows for you.

Cloudflare Changelog developers.cloudflare.com

What was announced?

Over on Cloudflare's Changelog, they announced that Workflows rollback handlers can now access the step context of the failed step. A ctx object is passed into your rollback handler, and from it you can read ctx.step.name, ctx.step.count, ctx.attempt, and the step configuration with its defaults applied.

The story so far

Workflows is all about being able to safely undo work when something fails partway through, and rollback handlers are how you write that undo logic. But until now, a rollback handler could not easily tell which step it was cleaning up or which attempt had failed. That made it fiddly to write clear rollback logs, or to tailor your recovery to the retry and timeout settings.

What changes

From now on, you can use ctx inside a rollback handler to reference the failed step's name and attempt count directly. For example, you can drop "which step failed, and with what error" straight into a refund reason, so it is much easier to trace later. The step configuration also carries the retry and timeout values, so you can shape your recovery logic around them.

Dive Deep

From ctx you can read ctx.step.name, ctx.step.count, ctx.attempt, and the step configuration (with defaults applied). The step configuration carries the retry and timeout details.

Here is what it looks like in code:

await step.do(
  "create charge",
  async () => {
    const charge = await createCharge();
    return { chargeId: charge.id };
  },
  {
    rollback: async ({ ctx, output, error }) => {
      const { chargeId } = output as { chargeId: string };
      await refundCharge(chargeId, {
        reason: `${ctx.step.name}: ${error.message}`,
      });
    },
    rollbackConfig: {
      retries: { limit: 3, delay: "30 seconds", backoff: "linear" },
      timeout: "5 minutes",
    },
  },
);

Pairing rollback with rollbackConfig lets you set the retry count, backoff, and timeout for the rollback itself. In the example above that is up to 3 retries, a 30-second linear backoff, and a 5-minute timeout. For the full set of options, check out the rollback options.

Wrap-up

  • Rollback handlers now receive a ctx object
  • You can read ctx.step.name / ctx.step.count / ctx.attempt, plus the step configuration with defaults applied
  • rollbackConfig lets you set retries and timeouts for the rollback itself
  • This one is for anyone writing Workflows that need to cleanly undo things like payments or external API calls when they fail