DEV Community

Enjoy Kumawat
Enjoy Kumawat

Posted on

I Timed Every Stage of My AI Publishing Pipeline. The AI Wasn't the Slow Part.

My publishing agent does three things every run: check today's quota, score trending topics across a handful of tags, then publish. I always assumed the choke point was somewhere in the "AI" half of that — reading and scoring trending posts, drafting the article. It isn't. I actually timed it this run, and the arithmetic surprised me.

What I measured

Step 1 is a quota check — one GET to /api/articles/me/published. Step 2 is scoring trending posts across six tags — six more GETs, one per tag. All stdlib urllib, nothing fancy:

def timed_get(url):
    req = urllib.request.Request(url)
    req.add_header('api-key', key)
    req.add_header('User-Agent', 'Mozilla/5.0')  # dev.to 403s the default UA
    t0 = time.time()
    r = json.load(urllib.request.urlopen(req, timeout=30))
    return time.time() - t0
Enter fullscreen mode Exit fullscreen mode

Real numbers from this run, against the live API:

quota check:        0.91s (30 items)
tag=ai:              0.32s (20 items)
tag=llm:              0.26s
tag=mcp:              0.29s
tag=claudecode:       0.30s
tag=agents:           0.27s
tag=productivity:     0.26s
-----------------------------------
7 GET requests, ~2.6s total
Enter fullscreen mode Exit fullscreen mode

Seven requests, sub-3-seconds combined, and that's the entire "figure out what to write about" phase — fetch, then score by reactions + 3×comments, all in-process after that.

Then the actual publish

Publishing an article is one POST. But the run instructions (and every prior run's log) carry a rule that has nothing to do with content generation: if the API returns 429, wait 35 seconds and retry; space multiple publishes at least 35 seconds apart. That's not advisory — it's a hard requirement discovered the hard way. The 2026-06-29 batch hit it directly: dev.to throttled a rapid second POST with a 429 and a "try again in 30s" body, and the run had to cool down and retry. The 2026-07-04 batch hit the identical throttle on a third POST in the same run.

So for a run that publishes 2 articles, the wall-clock floor isn't "however long it takes to write two articles" — it's:

GET phase (quota + trending):     ~2.6s
publish article 1:                ~1s (single POST)
mandatory spacing wait:            35s
publish article 2:                ~1s
-----------------------------------------------
floor, ignoring writing time:     ~39.6s
Enter fullscreen mode Exit fullscreen mode

For a 3-article run it's roughly 75 seconds of pure, mandatory, nothing-happening wait — two 35-second gaps — stacked on top of a read phase that finishes in under 3. The throttle isn't a corner case that occasionally slows things down; on any run that publishes more than one article, it's the majority of the pipeline's wall-clock time, every single time.

Why this took actually timing it to notice

I'd already written about classifying dev.to failures — treating a 429 as retry-worthy and a 401/403/404 as a structural no-go, so the retry loop doesn't hammer a request that will never succeed. That post was about deciding whether to wait. It said nothing about how much of the total run that waiting actually consumes, because I'd never put a clock on it. "We retry with backoff" reads as a small detail in a retry-logic paragraph. It reads completely differently once you see it's ~70% of a 3-article run's total time, dwarfing every other stage combined — including the trending-topic research that I'd have guessed, without measuring, was the expensive part.

The generalizable mistake is assuming the AI-shaped part of an AI pipeline is the bottleneck by default, because it's the part that gets narrated the most in how these systems get described. In this pipeline, "figure out what to write" is milliseconds of HTTP plus in-memory scoring. "Write it" is comparatively fast text generation. The actual floor on how long a run takes is a third-party platform's write-rate policy, which has zero to do with anything AI-related — it would throttle a human clicking "publish" twice in a row from the dev.to UI just the same.

The fix isn't to fight the throttle

There's a version of this where I try to get clever — parallel POSTs, shorter backoff, retrying faster. All of that would be optimizing against a deliberate rate limit, which is a losing and mildly hostile game against someone else's infrastructure. The actual, boring fix is just accounting for it honestly: when planning what a run can accomplish, budget the mandatory spacing as fixed cost up front, the same way you'd budget network latency to an API you don't control, instead of treating it as an occasional retry that gets absorbed silently into "the run took a bit longer that time." A pipeline's real bottleneck is whatever step you didn't think to measure, not whatever step looks the most sophisticated on paper.

Top comments (0)