Skip to content

Step 10 — Scheduled work and email

About 25 minutes. Branch: step-10.

The one new idea: a cron job is an HTTP request to your own URL.

Cron, and the thing to unlearn

appmecca.yaml @ step-10
cron:
  - name: weekly-digest
    schedule: "0 7 * * 1"
    url: /api/cron/digest
    service: web
    method: POST
    timeout: 60

There is no command: here, and nowhere to put one

If you have used cron anywhere else, you expect to name a command. On this platform you name a URL. The platform makes an HTTP request to your own running service on a schedule; your app does the work behind the endpoint; the response is the outcome.

All six fields, and what each is really for:

Field
name how you refer to it in mecca cron
schedule standard five-field cron, in UTC
url a path on one of your services. Must start with /
service which service to call. Required once an app has more than one — and yours has two, so leaving it out is an error rather than a guess
method GET or POST. POST is the default and right for anything that changes state
timeout seconds, 5–300, default 30

timeout is the one that shapes your design. If the work cannot finish inside it, it does not belong in the endpoint — put the item on the worker's queue and return immediately. You already have a worker for exactly that.

And since the endpoint is reachable, treat it as reachable: make it safe to call twice, because one day it will be.

Try it without waiting a week

mecca cron list tally
mecca cron trigger tally weekly-digest
mecca cron history tally

history gives you what happened and what the endpoint replied.

mecca cron disable tally weekly-digest
mecca cron enable tally weekly-digest

Email

email:
  enabled: true

One line, and three variables arrive: a relay URL, a token scoped to this app and this branch, and the address you are allowed to send as.

httpx.post(
    url,
    headers={"Authorization": f"Bearer {os.environ['APPMECCA_MAILER_TOKEN']}"},
    json={"to": [to], "subject": subject, "text": text},
    timeout=10.0,
)

You do not choose the From address

The relay stamps it. That is what stops one app sending as another, and it is why there is no mail credential here for you to leak.

There is a quota — a rolling 24 hours, per app per branch — and the relay tells you where you stand in the response headers rather than making you guess.

Notifications fail softly, deliberately

app/mailer.py returns False and logs. It never raises.

That is a design decision worth stealing: a roadmap board that cannot send a notification should still accept the idea. The submission is the user's work; the email is yours. Do not lose theirs over yours.

mecca email status tally -b tutorial
mecca email events tally

events is the log of what was sent, delivered, bounced or complained about.

What you should see

  • mecca cron trigger runs immediately and history records the reply.
  • A submission produces an email, if you set an owner address.
  • mecca email events lists it.

If it didn't work

Symptom Try Usually
Cron never runs mecca cron list Disabled, or service: missing on a multi-service app
It runs and fails mecca cron history The endpoint 500s, or exceeded timeout
No email mecca email status Not enabled, or the address is not verified
429 in the logs mecca email status Quota. The reset time is in the response

Reset to the reference

git fetch upstream && git reset --hard upstream/step-10 && git push --force origin tutorial

Next: Step 11 — A drive and a bucket