Weekly Padgett

No. 0032 min read

Never post twice. Yes, even when I run the damned thing twice.

grime95.com posts daily fiction to a website, Facebook and Instagram. Posting was easy. Keeping a retry from posting the same damned thing again took some work.

A person handles a white frosted cake inside a cardboard box beside another cake and metal trays.
File photoDramatization. No python was harmed.

You want a script that posts something once a day, forty lines should do it. Then you get to spend the next week figuring out what happens when those forty lines half-work.

I run grime95.com[1]Ref. 1grime95.com grime95.com, a serialized fiction site publishing one fictional small-town booking record every day at noon Eastern. Each goes to a static site (a GitHub Pages[2]Ref. 2GitHub Pages pages.github.com repo), a Facebook Page, and Instagram. Cron[3]Ref. 3Cron en.wikipedia.org does it. Twenty percent of that script took eighty percent of the thought, most of it about what could go wrong.

My billing mediation habit kicks in here, because I've spent a lot of time reconciling things and I want a ledger I can check. I used SQLite[4]Ref. 4SQLite sqlite.org, one row per (entry, channel). Status: pending | success | uncertain.

Three statuses, because sometimes I genuinely don't know what happened.

When a POST to Meta's Graph API[5]Ref. 5Meta's Graph API developers.facebook.com throws, you don't know whether the post exists. Maybe it completed and the response disappeared. Maybe the token expired and nothing happened. Instagram takes two calls, create a container and publish it, so it can half-happen. A leftover container expires on its own, but isn't easily distinguished from one that published.

POSTs get exactly one attempt. An exception marks the row uncertain, and the script stops touching that (entry, channel) pair. On the next run, GETs retry freely. Reading is idempotent, so I can keep looking without posting another copy.

Every channel adapter gets a checkpoint callback. The instant it has a remote ID, it calls that callback.

Verification can fail. The process can get killed. The ledger already knows a post with that ID exists, so the next run sees remote_id and doesn't repost. Instagram checkpoints even the container ID as container:<id> before publishing. Half-done counts as something I want written down.

About 480 lines of Python. Standard library plus Pillow[6]Ref. 6Pillow pillow.readthedocs.io for image checks. I wrote it in an afternoon and I'm proud of the thing. Getting the failure states right took the week after.

I don't want to babysit it every day at noon.

References

  1. grime95.com grime95.com ↩
  2. GitHub Pages pages.github.com ↩
  3. Cron en.wikipedia.org ↩
  4. SQLite sqlite.org ↩
  5. Meta's Graph API developers.facebook.com ↩
  6. Pillow pillow.readthedocs.io ↩
pythoncronmeta-graph-apiidempotencygrime95

More on this beat