Instead of creating a separate Render cron service for each scheduled task (each with its own build step, env vars, secret group attachments, and billing), consolidate into a single frequently-running cron service that dispatches based on the current time.
Pattern:
# Single cron service running every 10 minutes (*/10 * * * *)
set -o errexit
# Always-run tasks
python -m myapp do-frequent-thing
# Time-gated tasks
HOUR=$(date -u +%H)
MINUTE=$(date -u +%M)
if [ "$HOUR" = "10" ] && [ "$MINUTE" = "30" ]; then
python -m myapp do-morning-thing
fi
if [ "$HOUR" = "21" ] && [ "$MINUTE" = "00" ]; then
python -m myapp do-evening-thing
fiRequirements:
- The scheduled times must align with the dispatcher's cron interval (e.g.
*/10hits:00,:10,:20,:30,:40,:50— so10:30and21:00both hit exactly) - The dispatched tasks should be idempotent so timing jitter or double-fires are harmless
- Tasks should enqueue work to a job queue rather than running inline, keeping the cron service lightweight
Benefits:
- Fewer services = less build time, lower billing, fewer manual secret-group attachments
- Single place to see all scheduled dispatch logic
- Shared env/secrets without per-service dashboard configuration