Vibes DIY
Vibes DIY / Docs
creator docs · pattern

Scheduled self-maintenance

The problem: anything operational decays. Tokens expire, failed jobs need retries, old records pile up, external state drifts. Traditionally this is a crontab on a server someone has to remember exists.

The pattern: a scheduled handler that treats maintenance as ordinary document work — read state, decide, write it forward — so the app keeps itself alive.

jsexport const config = { scheduled: { interval: "1m" } };

export async function scheduled(event, ctx) {
  const vault = await ctx.db.query({ db: "vault" }); // admin mode: unfiltered
  for (const cred of vault.filter((d) => d.kind === "token")) {
    if (needsRotation(cred, event.scheduledTime)) {
      try {
        const fresh = await rotate(cred); // fetch() to the platform's API
        await ctx.db.put({ ...cred, token: fresh.token, refreshedAt: event.scheduledTime, needsReauth: false });
      } catch (e) {
        await ctx.db.put({ ...cred, needsReauth: true, lastError: String(e && e.status) });
      }
    }
  }
}

meta-hub runs this shape every minute in production: it refreshes Meta's 60-day tokens once they're older than 7 days, verifies fresh pastes via the platform's /me endpoint, probes its own egress lanes, and advances pending publish requests — all from one tick function.

The discipline that makes ticks safe

A 1-minute timer amplifies every mistake, so the production rules:

  • Idempotent ticks. Each tick reads current state and converges it; a missed or doubled tick changes nothing. Never accumulate work in handler memory — the documents are the state.
  • Bound your retries on the doc. An attempts counter and a MAX_ATTEMPTS cap turn infinite retry loops into error states a human can see. Meta containers that aren't FINISHED just retry next tick — bounded.
  • Respect upstream rate limits structurally. Bluesky's createSession allows ~300/day — so meta-hub mints session JWTs from a cached session and touches the password-based call only as a fallback, never on the timer.
  • Degrade to a visible state, never to silence… and never to noise. A dead credential flips needsReauth and the dashboard shows NEEDS RE-AUTH; held work resumes untouched after a fresh paste. Failures write status docs — they don't post, don't spam, don't lose the queue.
  • Keep admin-mode writes small. scheduled runs as the owner with the access override (guide), so a buggy write fails silently-wrong rather than forbidden. Small, well-guarded writes.

Composes with

The write-only vault (rotation is why the vault holds data, not config), doc state machines (the tick is the queue's consumer), and the operator console (every tick's status writes are the dashboard's live feed).