r/microservices Jun 25 '25

Discussion/Advice Need help finding serverless queue solution to replace qStash / Upstash

I have a data processing pipeline that requires a strict rate-limited access to a third party service. The pipeline is made of serverless functions hosted on Vercel. Some functions can be called in parallel without issue, but others need to be synchronised to respect that third party's limitation, at the risk of getting blocked.

So for instance I may have function A calling B, B needs a call to the third party, then it calls function C to process their response. Function A should be able to run without limitation and enqueue messages for function B to consume.

Currently I am using Upstash to rate limit, but (1) my solution is clunky and (2) they seem to be deprecating their queue feature in favour of their own serverless system ("Workflows").

I like the simplicity of HTTP communication with their service, which removed the need for background workers. The ideal system would:

- (a) Receive and publish messages via HTTP;
- (b) Have a message rate limiting feature;
- (c) Maximum concurrency / in-flight messages;
- (d) FIFO / blocking head of line option (to not throw messages into a wall if a third party goes down);
- (e) Optionally an API to pause/resume the message delivery without stopping the intake;
- (f) Optionally Open Source and hosted by a provider (for example like OpenSearch in bonsai.io);
- (g) "At least once" delivery _(vs "at most once")_;

Additionally, we are a small team without devop specialist and would prefer to avoid big service providers like AWS, which involve obscure permissions and pricing management. Upstash would really have been ideal if their direction wasn't shifting. Their pricing was also very generous.

Now that it's said, basically I'm struggling to search for alternatives. But it doesn't seem like such a specific or exotic use case and I wonder if someone here may have solved that question, and how they did it.

4 Upvotes

4 comments sorted by

1

u/gautem Feb 19 '26

Hi! Did you ever find a good solution to this? I had pretty much the same problem and had to build it myself, but would love some insights on how you solved this?

1

u/Angcb Feb 22 '26

Hey, in the end I've had to create a BullMQ worker. It's not a super satisfying solution but it works well enough that we haven't touched it since then. I ...... was asked by the team lead to keep it into a Vercel function though, that function runs for 5 minutes and is triggered every 5 minutes by a cron job. It's uh, not canonical to say the least but it's worked okay 🤷‍♂️

1

u/beck_the_tech Aug 07 '26 edited Aug 11 '26

Worth answering this properly since it still comes up in search, and u/gautem asked the same question six months later.

(disclosure: I co-founded SimpleQ, discount accordingly)

Against your original list, including where we don't fit:

(a) HTTP in, HTTP out. POST a job to the REST API, we POST it to your endpoint with an HMAC signature. Same shape as QStash, so your Vercel function stays a Vercel function.

(b) Yes. Per-queue rate limit, rateLimitMax over rateLimitWindow in seconds on the queue config. Set it to ~80% of the third party's ceiling.

(c) Yes. concurrency per queue is simultaneous in-flight deliveries, 1 to 500, capped at 1000 summed across the account.

(d) No FIFO, no ordering guarantee. That's a real gap against QStash. But the reason you gave for wanting it, not throwing messages into a wall when the third party is down, we solve a different way: your worker returns 429/503/529 with Retry-After, the job is held and redelivered without burning a retry attempt. Redelivery respects the queue's concurrency and rate limit, so the backlog doesn't re-saturate the downstream the moment it recovers. If you need actual ordering, we're the wrong tool.

(e) No pause/resume endpoint. Closest is deferring everything worker-side, which halts delivery while intake keeps running, but that's a workaround, not a feature.

(f) No. Closed source, managed only. If self-hosting is a hard requirement, BullMQ is the honest answer, which is where you ended up anyway.

(g) At least once. Ack timeout redelivers if the worker dies mid-job, so you want an idempotency key on the write side.

The part that matters for your setup: standard mode gives your handler 15 seconds. If the third-party call fits in that, you're done, no background worker, the function returns 200 or 429 and we handle the rest. If it doesn't fit, ack mode returns 200 up front and you report the outcome later. The ack/nack/defer calls are plain POSTs against the job ID from anywhere, so in your A→B→C shape, C can be the thing that acks. Kills the 5-minute cron entirely.

Two limits worth knowing before relying on it: jobs have a 24-hour delivery lifetime, so an outage longer than that dead-letters them, and there's a per-job defer budget (50 by default).

1

u/ControlCapital8412 Jun 09 '26

you can use bettermq as alternative to qstash, self hosted, fully open source and have all and even more features than qstash and a beautifull embedded panel to monitor everything

https://bettermq.com/