Getting started
deadbeat runs a Python script on a schedule, in a sandbox, without you owning a server. This is everything you need to know to get a job running and keep it running.
The loop
- Create a job and paste a script. One file. It runs as
python main.py. If you don't have one handy, start from a template on the dashboard - each is a complete working script. - List anything you import that isn't in the standard library.
Put it in the requirements.txt box next to the script, one per line, the
same as a normal
requirements.txt. We install it into the sandbox before running. If you skip this and your script importsrequests, we'll tell you before you waste a run. - Run it once. You get stdout, stderr, the exit code and the duration straight away.
- Give it a schedule. This is the part that makes it a cron job rather than a script you ran once.
Schedules
Pick a preset - every 15 minutes, hourly, daily, weekly, monthly - or write a standard five-field cron expression. Cron expressions are interpreted in UTC, with no per-job timezone, so a "9am daily" job is 9am UTC wherever you are.
A job with no schedule is still useful: it sits there and runs when you click run, which is a fine way to keep a script you run by hand.
Output and files
Everything your script prints is captured per run - the last 50KB of stdout and stderr each - and kept in the run history.
Anything your script writes to /out comes back as a
file you can view or download from that run. That's the way to
produce a report, a CSV, a scraped dataset. A good habit is to check the
directory exists first, so the same script still works on your laptop:
from pathlib import Path
out = Path("/out")
if out.is_dir():
(out / "report.md").write_text(brief)
else:
print(brief)
Files are kept per job against a size budget, oldest evicted first, so a daily job writing a small file keeps years of history.
Secrets
API keys and tokens go in the job's environment variables, not in the script. They're encrypted at rest and decrypted only for the moment your job runs. Read them the ordinary way:
import os
token = os.environ["API_TOKEN"]
One caution: if your script lets an exception carrying a secret escape - a URL with a token in the path is the classic - that text lands in the run's captured output. We strip values we know about, but handle your own errors rather than relying on it.
When something breaks
If a scheduled run fails, we email you. Once when it breaks, again at intervals while it stays broken, and once more when it recovers. Manual runs don't email - you're watching those happen.
Exit non-zero when your job fails. This is the one thing worth getting right. A script that catches an exception, logs it, and exits 0 looks like a healthy run forever while doing nothing - the exact failure this product is named after. If the work didn't happen, say so:
import sys
if rows_written == 0:
print("no rows written", file=sys.stderr)
sys.exit(1)
Limits
- Python 3.12.
- One script per job - no multi-file projects or imports between jobs.
- Runs are capped at 300 seconds and 256MB of memory.
- Your script can reach the internet, but not other jobs or anything private on our side.
- Scripts, dependencies and output all have size caps; you'll be told if you hit one rather than silently truncated.
Stuck?
Email hello@deadbeat.dev, or just reply to any email deadbeat sends you - both reach a person.