1 min lesson
Production automation, four attributes
Use "Production automation, four attributes" to explain each part and the role it plays.
Step 1 of 3
The four properties graders look forwhat separates a script from a toy
Production automation, four attributes
- Idempotent
- Running it twice produces the same end state - you check-then-act, never blind-create
- Resilient
- Pagination, retries with backoff on 429/5xx, timeouts and a clear failure path
- Observable
- Structured logs, a summary of what changed and an alert when a run fails
- Safe
- A
--dry-runthat prints the diff without mutating and secrets pulled from a vault not the source
If you can name these four and show them in code, you've cleared most of the scripting screen before writing a single helper.
Learn more
Full explanation
Talk to a SaaS API the way the API expects
Talk to a SaaS API the way the API expectsOkta, Google, Slack all bite the same way
Every IT-facing API has the same three traps: it pages its results, it rate-limits you and it occasionally 500s mid-batch. A senior answer wires all three into a small reusable client rather than copy-pasting requests.get everywhere.
Idempotent Okta group-membership sync with paging + retry/backoff
import os, time, logging, requests
OKTA = os.environ["OKTA_ORG_URL"] # injected, never hard-coded
TOKEN = os.environ["OKTA_API_TOKEN"] # from the secrets manager
S = requests.Session()
S.headers.update({"Authorization": f"SSWS {TOKEN}"})
log = logging.getLogger("jml")
def get_all(path):
"""Follow Okta's Link: rel=next paging, retry on 429/5xx."""
url, out = f"{OKTA}{path}", []
while url:
for attempt in range(5):
r = S.get(url, timeout=30)
if r.status_code == 429 or r.status_code >= 500:
wait = int(r.headers.get("Retry-After", 2 ** attempt))
log.warning("throttled, sleeping %ss", wait); time.sleep(wait); continue
r.raise_for_status(); break
else:
raise RuntimeError(f"gave up on {url}")
out += r.json()
url = r.links.get("next", {}).get("url")
return out
def converge_membership(group_id, desired_ids, dry_run=True):
current = {u["id"] for u in get_all(f"/api/v1/groups/{group_id}/users")}
add, remove = desired_ids - current, current - desired_ids
log.info("group %s: +%d -%d", group_id, len(add), len(remove))
if dry_run:
return {"add": sorted(add), "remove": sorted(remove)} # show the diff, change nothing
for uid in add:
S.put(f"{OKTA}/api/v1/groups/{group_id}/users/{uid}", timeout=30).raise_for_status()
for uid in remove:
S.delete(f"{OKTA}/api/v1/groups/{group_id}/users/{uid}", timeout=30).raise_for_status()
return {"added": len(add), "removed": len(remove)}Notice the shape: read the current state, compute a diff against desired and apply only the delta. That's a reconcile-and-converge loop and it's idempotent for free because a second run finds nothing to change.