Skip to content
A dark grid: six empty rectangles stacked on the left merge into a single teal line that runs into one filled rectangle, then into a small ringed dot; from the dot two branches leave — a solid line to a box at the upper right and a dashed line to a box at the lower right.

“A policy applied inconsistently is worse than one not applied at all.”

The cron jobs were the business

Six daily jobs that handled renewal, downgrade, dunning and re-engagement — the revenue cycle, running on a schedule.

Get in touch
A US marketplace for truck services · technical leadership · 2022–2026 · same engagement
6
daily jobs carrying the revenue cycle
55
email templates behind one service
7
days late, then an automatic downgrade
Summary

Scheduled jobs are usually maintenance: clean this up, expire that, send a digest. On this platform they were where the money was.

Six of them ran daily. Between them they reminded advertisers before expiry, downgraded listings that fell too far behind on payment, processed recurring charges, chased unverified listings, ran a re-engagement campaign timed to the annual cycle, and warned fleet operators about upcoming vehicle inspections.

The problem

The product sold annual advertising. That means revenue does not arrive continuously — it arrives at a renewal moment that is different for every customer, and if that moment passes unattended the money doesn’t arrive at all.

The constraint

Nobody was going to watch several thousand expiry dates by hand. And a rule like “downgrade after non-payment” cannot live in someone’s judgement, because applied inconsistently it is worse than not applied at all. So the commercial policy had to live in code, and run without anyone deciding to run it.

What we did

  1. We made renewal the central job

    It finds listings approaching expiry, sends reminders, and — for listings more than seven days late — automatically downgrades them, updates the invoice, and re-indexes the record so the change is visible in search immediately.

    Seven days, then downgrade
  2. A downgrade you cannot see in search is not a downgrade

    It is a downgrade in the database only, and the advertiser keeps the placement they stopped paying for. That is why re-indexing belongs in the same job rather than in a nightly batch.

    Visible immediately
  3. We handled recurring payments with all three outcomes

    Success, failure and upcoming charge each have their own message. Payment failure is not an error state to log — it is a conversation with a customer who probably wants to keep the service.

    A conversation, not a log
  4. We timed re-engagement to the annual cycle

    A three-step campaign at roughly 179, 182 and 186 days from a listing’s last update. Not arbitrary: half a year out from renewal, a listing with stale information is a listing whose owner has stopped thinking about it — and that is who fails to renew.

    179 · 182 · 186 days
  5. We chose the channel per job, and kept one route out

    Reminders about unfinished draft listings go in-app rather than by email: someone halfway through creating a listing doesn’t need to be chased into their inbox, they need to be met where they left off. Every job followed the same shape — query the database, take a template from object storage, write a record, put a message on a queue — and one service did the actual sending. Outside production that service redirected all mail to a test address, which made emailing real customers from staging structurally impossible.

    One route out, one redirect
THE SAME SHAPE FOR EVERY JOB — FIVE STEPS
The query who is due

Every job starts with a query: listings about to expire, charges coming up, listings untouched for 179 days. The criterion is commercial policy written as a condition, not as someone’s judgement.

All six jobs travel the same path, and all mail leaves through one door. That is why a single redirect is enough for staging to never write to a real customer.

The result

  • Six daily jobs carrying renewal, downgrade, dunning and re-engagement
  • Commercial policy applied identically to every account, without anyone deciding to apply it
  • 55 email templates behind a single sending service

What we’d do differently

The jobs ran daily and reported nothing but errors. Nobody could see how many listings had been downgraded this week, or whether the re-engagement campaign moved anything at all. Business logic that runs unattended needs a business-level report, not just a log — otherwise you find out it stopped working when someone asks why revenue dipped.

Related
Measuring what the customer pays forThe same revenue cycle, seen through measurement.Four re-platformings, zero downtimeThe system these jobs ran inside.
All 18 case studies
  • AWS Lambda
  • SQS
  • MySQL
  • Handlebars
  • Node.js

Does your revenue depend on dates nobody watches?

Get in touch

Systems that can’t stop — from architecture to production.

© 2026 Micro Tech, Sarajevo