Slack alert on uncaught exception in main()#97
Conversation
Wraps main() in try/except and posts the traceback to a SLACK_WEBHOOK_URL (passed via GitHub Actions secret) so failures in the scheduled run surface in #cutepetsboston-alerts. Re-raises the exception so the workflow still fails. Closes #74 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| INSTAGRAM_PAGE_ACCESS_TOKEN: ${{ secrets.INSTAGRAM_PAGE_ACCESS_TOKEN }} | ||
| BLUESKY_HANDLE: ${{ secrets.BLUESKY_HANDLE }} | ||
| BLUESKY_PASSWORD: ${{ secrets.BLUESKY_PASSWORD }} | ||
| SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} |
There was a problem hiding this comment.
Maybe we should have a dev slack webhook so we can distinguish between dev and prod errors
There was a problem hiding this comment.
I agree with being able to distinguish between environments. Instead of splitting SLACK_WEBHOOK_URL I added a new environment variable: APP_ENV.
I added it to our example env and to our workflow ymls and use that for the env-specific logic. I think this will be generally useful. I can add it to a README too, if you agree with the direction.
| raise | ||
|
|
||
|
|
||
| def notify_slack_of_exception(tb_text): |
There was a problem hiding this comment.
let's put the notify_slack_of_exception below the run function just so that the function definition order matches the order they are called in the main function (this makes onboarding people onto the slightly easier)
| def notify_slack_of_exception(tb_text): | ||
| webhook_url = os.environ.get("SLACK_WEBHOOK_URL") | ||
| if not webhook_url: | ||
| print("SLACK_WEBHOOK_URL not set; skipping Slack alert.") |
There was a problem hiding this comment.
should we print the traceback in this case? We'll still want to see the error
| raise | ||
|
|
||
|
|
||
| def notify_slack_of_exception(tb_text): |
There was a problem hiding this comment.
| def notify_slack_of_exception(tb_text): | |
| def notify_slack_of_exception(traceback_text): |
| return | ||
|
|
||
| workflow = os.environ.get("GITHUB_WORKFLOW", "local run") | ||
| repo = os.environ.get("GITHUB_REPOSITORY", "") |
There was a problem hiding this comment.
| repo = os.environ.get("GITHUB_REPOSITORY", "") | |
| repo = os.environ.get("GITHUB_REPOSITORY") |
| header = f"CutePetsBoston run failed in *{workflow}*" | ||
| if run_link: | ||
| header += f" (<{run_link}|view run>)" | ||
| text = f"{header}\n```{tb_text.strip()[-2500:]}```" |
There was a problem hiding this comment.
can we put 2500 in a constant variable and also leave a comment on why that number was chosen?
|
|
||
| run(sources, posters) | ||
| except Exception: | ||
| notify_slack_of_exception(traceback.format_exc()) |
There was a problem hiding this comment.
Maybe include when the error is prod (may need an extra env var in workflows step). Either include is prod or is manual run in the slack message
- Move notify_slack_of_exception below run() so definitions match call order - Always print traceback (even when SLACK_WEBHOOK_URL is unset) - Rename param tb_text -> traceback_text - Drop empty-string default on GITHUB_REPOSITORY - Extract MAX_TRACEBACK_CHARS constant with comment on Slack size limit - Add APP_ENV (dev/prod) and GITHUB_EVENT_NAME to Slack message header so prod vs dev and scheduled vs manual runs are distinguishable - Add APP_ENV to .env.example Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
This PR includes adding |
Summary
main()in a try/except so any uncaught exception is caught, the traceback is posted to Slack, and then re-raised so the GitHub Actions run still fails.notify_slack_of_exceptionwhich posts toSLACK_WEBHOOK_URL(no-op if unset), including the workflow name and a link to the GitHub Actions run when those env vars are present. Truncates the traceback to the last 2500 chars to stay well under Slack's message size limit.SLACK_WEBHOOK_URLrepo secret into bothdev.ymlandprod.ymlworkflows.Closes #74
Setup (already done outside this PR)
#cutepetsboston-alertsSlack channel created with an Incoming Webhook.SLACK_WEBHOOK_URLadded as a repo secret in GitHub.Test plan
SLACK_WEBHOOK_URLand forcing an exception — message appeared in#cutepetsboston-alertswith the traceback.tests/test_main.pystill passes.workflow_dispatchagainst a branch that intentionally raises).🤖 Generated with Claude Code