HowToProd.com

DesignBeaver doesn't have a bursty batch job. Everything I run sits on the same Fargate service, all day, whether anyone's using it or not. But the question comes up in my head every time a feature idea involves doing real work off the request path, and I've never actually written down what I'd pick. So here it is, argued from the tradeoffs rather than from a war story I don't have.

The Job That Doesn't Exist Yet

The shape I keep imagining is something like bulk diagram export, or regenerating a batch of thumbnails after a rendering change. Work that's triggered by user behavior, so it's spiky and unpredictable, over almost as soon as it starts. Nothing about it needs to run continuously. That's the whole reason it's an interesting decision and not an obvious one — a steady background worker would just go on the existing Fargate task without a second thought.

Where Lambda Actually Wins on Paper

Lambda is built for exactly this pattern. You pay per invocation and per millisecond of actual execution, so a job that fires ten times one afternoon and then not again for three days costs almost nothing between bursts. Fargate doesn't have that property. A standing task burns money whether it's doing anything or not, and even running it as a one-off ECS task instead of a service means eating image-pull and startup time on every invocation, which isn't so different from a cold start except you rarely hear it called one. On raw fit, this isn't close. This is the exact case Lambda's billing model was built to reward: short, bursty jobs that spend most of their time not running. Pretending otherwise because Fargate is what I already know would be the kind of decision that only looks reasonable from inside my own habits.

The Line That Sends It Back to Fargate

The part I had to actually think through was where that stops being true. Two things matter more than "is it bursty": how long each run takes, and how sporadic the bursts really are. Duration has a hard stop built in: Lambda cuts you off at fifteen minutes no matter what the cost math says, so anything that can run genuinely long, a large export job rather than a quick one, is disqualified before cost ever enters the conversation.

Below that ceiling, it's a cost question. A job that runs for a few seconds and fires a handful of times a day, an EventBridge rule kicking off a single Lambda invocation, sits right where the per-invocation math pays off: a cold start of a second or two against a Fargate RunTask that takes closer to thirty or sixty seconds just to pull the image and boot. Push the frequency up and that gap stops mattering. A job that fires often enough in a day that it stops looking like a burst and starts looking like a trickle erodes the cost advantage fast, and at that point the same EventBridge rule pointed at an ECS RunTask instead does roughly the same job without a second deploy path to maintain. That deploy path is the real cost: its own build step, its own place to watch for failures, on top of an observability setup that's already thinner than I'd like. That operational tax matters more than anything Lambda charges per invocation.

One Job Doesn't Justify a Second Pipeline. Five Might.

Here's the part I wasn't sure of until I wrote it out: the threshold for adding Lambda at all isn't really about any single job's shape. It's about how many jobs like it you're going to have. Standing up a second deploy pipeline, a second packaging format, a second thing to check when something breaks, is expensive to justify for one export job and cheap to justify once you've got several background tasks that all fit the same profile. I don't have a real number for where that flips — five in the title is a guess, not something I measured. What I do trust is the shape of it: the first one almost never clears the bar on its own, and somewhere around four or five you've stopped building a one-off exception and started maintaining a pattern, which is the point the second pipeline starts paying for itself instead of just costing.

That's the whole rule as one picture: three gates, and Fargate is the default landing spot at every single one of them until a job clears all three.

So if this job ever gets built, it's landing on Fargate as a one-off ECS task first, not Lambda, even though Lambda is the better fit in isolation. I'd rather eat a slower cold start on something I already know how to run than adopt a second compute model for one function. That changes the day a second job like it shows up and the math flips from "is this worth the tax" to "I'm already paying the tax, why not use it." If you're solo or small and you're weighing this for your first background job, my actual advice is to skip the Lambda research entirely until you're picking a home for your third one. "Right tool for the job" is optimizing for the wrong variable when the job in question is the only one you have.