Summary
vercel.json's crons array currently schedules both /api/v1/keepers/accrue (every 15 minutes) and /api/v1/keepers/rebalance (hourly, added in #469's PR). Neither can actually run: Vercel's Hobby plan restricts Cron Jobs to once per day, and both schedules are more frequent than that. Vercel's own deployment check fails with:
Hobby accounts are limited to daily cron jobs. This cron expression (*/15 * * * *) would run more than once per day. Upgrade to the Pro plan to unlock all Cron Jobs features on Vercel.
Motivation
This means the accrual keeper has not actually been running on any schedule since it was merged in #484: nothing is triggering it in production today, so Blend-backed vault TVL/APY has likely been stale since then, contradicting apps/docs/operations/accrual-keeper.md's documented 15-minute staleness guarantee. This is a live, silent gap, not just a blocker for the new rebalance keeper.
Proposed Solution
Discussed three options; moving scheduling off Vercel Cron entirely was chosen over upgrading to Pro or downgrading both keepers to a daily cadence (which would materially weaken the accrual keeper's existing staleness guarantee):
- Remove both entries from
vercel.json's crons array
- Add a GitHub Actions workflow (e.g.
.github/workflows/keepers.yml) with two schedule: triggers (*/15 * * * * for accrue, 0 * * * * for rebalance) that curl the respective endpoints with Authorization: Bearer ${{ secrets.CRON_SECRET }}
- Add
CRON_SECRET as a GitHub Actions repository secret (same value already used for Vercel's own CRON_SECRET)
Confirmed this doesn't violate GitHub's usage policies: the schedule trigger calling an external endpoint on a timer is a standard, documented use case, well outside GitHub's actual abuse categories. Two operational caveats to design around, not blockers:
- GitHub auto-disables scheduled workflows after 60 days of repository inactivity (no pushes) — needs the repo to stay active or someone to notice and re-enable it
- Scheduled workflow timing is best-effort, not exact-to-the-minute under platform load, acceptable for a 15-minute/hourly keeper interval
Scope
| Field |
Value |
| Area |
API |
| Protocol affected |
None |
| Network |
testnet |
| Breaking change? |
No (changes trigger mechanism only, not endpoint behavior) |
Alternatives Considered
- Upgrade to Vercel Pro: removes the restriction with no code changes, but is a billing decision, not something to default into silently.
- Downgrade both keepers to daily cron: stays on Hobby with native Vercel Cron, but weakens the accrual keeper's already-documented 15-minute staleness guarantee to a daily one, a real behavior regression for existing functionality.
Acceptance Criteria
Summary
vercel.json'scronsarray currently schedules both/api/v1/keepers/accrue(every 15 minutes) and/api/v1/keepers/rebalance(hourly, added in #469's PR). Neither can actually run: Vercel's Hobby plan restricts Cron Jobs to once per day, and both schedules are more frequent than that. Vercel's own deployment check fails with:Motivation
This means the accrual keeper has not actually been running on any schedule since it was merged in #484: nothing is triggering it in production today, so Blend-backed vault TVL/APY has likely been stale since then, contradicting
apps/docs/operations/accrual-keeper.md's documented 15-minute staleness guarantee. This is a live, silent gap, not just a blocker for the new rebalance keeper.Proposed Solution
Discussed three options; moving scheduling off Vercel Cron entirely was chosen over upgrading to Pro or downgrading both keepers to a daily cadence (which would materially weaken the accrual keeper's existing staleness guarantee):
vercel.json'scronsarray.github/workflows/keepers.yml) with twoschedule:triggers (*/15 * * * *for accrue,0 * * * *for rebalance) thatcurlthe respective endpoints withAuthorization: Bearer ${{ secrets.CRON_SECRET }}CRON_SECRETas a GitHub Actions repository secret (same value already used for Vercel's ownCRON_SECRET)Confirmed this doesn't violate GitHub's usage policies: the
scheduletrigger calling an external endpoint on a timer is a standard, documented use case, well outside GitHub's actual abuse categories. Two operational caveats to design around, not blockers:Scope
Alternatives Considered
Acceptance Criteria
vercel.json'scronsarray no longer schedules either keeper endpointCRON_SECRETapps/docs/operations/accrual-keeper.mdandapps/docs/operations/migration-keeper.mdupdated to describe the actual trigger mechanism