Retry expired Instagram media URLs via instaById before giving up - #41
Open
rejas wants to merge 1 commit into
Open
Retry expired Instagram media URLs via instaById before giving up#41rejas wants to merge 1 commit into
rejas wants to merge 1 commit into
Conversation
Instagram issues some (typically older) media noticeably shorter-lived signed CDN URLs than others fetched in the same batch, so a media_url embedded on the WordPress side can already be expired by the time a visitor loads it — even though our own cache entry for that batch is still well within its 12h TTL. The proxy would just return a plain 400, leaving the frontend with no way to recover (see the paired frontend fix in vvp_divi5_extensions for the "Bild nicht verfügbar" fallback this produces). Thread the Instagram post id (and, for a carousel slide, its child id) and account through to the proxy URL, bound into the HMAC signature via a new generate_token_with_context() alongside the existing url-only generate_token(). On a failed primary fetch, resolve_media_url now does one retry: re-fetch that single post from Instagram (fetch_fresh_media_url) to get a freshly signed URL, then fetch that. Backward compatible: links generated before this deploy (or by a post missing an 'id', which shouldn't happen but is technically optional in the API response) carry no post_id and are verified and served exactly as before — generate_token(url) unchanged, replace_media_urls() unchanged and still used/tested as-is. replace_media_urls_for_posts() is the new, additive, Instagram-feed-specific counterpart that instaFeed now uses instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR improves resilience of the Instagram media proxy by allowing a single, signed, context-aware retry when an embedded Instagram CDN media_url has expired before the proxy cache TTL.
Changes:
- Add context-bound HMAC tokens (
generate_token_with_context) and Instagram-feed-specific URL rewriting (replace_media_urls_for_posts) so proxy URLs carrypost_id/child_id/account. - Update
resolve_media_urlto retry once by calling the Instagram Graph API for a freshmedia_urlwhen the initial fetch fails (context links only). - Extend test coverage to validate context binding, fallback behavior, and backward compatibility for legacy (url-only) tokens.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| proxycache/helper.py | Adds context-bound token generation and an Instagram-feed-specific media URL rewriter that includes post/account context. |
| proxycache/services/resolve_media_url.py | Adds a fetch helper and a one-shot retry path that re-fetches a fresh Instagram media_url on failed primary fetch (context links only). |
| proxycache/services/insta_feed.py | Switches instaFeed to the new post-aware URL rewriting and adds fetch_fresh_media_url used by the proxy retry. |
| proxycache/tests.py | Adds tests for context binding, carousel child handling, retry behavior, and legacy behavior preservation. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+119
to
+123
| url = f"https://graph.instagram.com/v15.0/{post_id}" | ||
| params = { | ||
| "fields": "media_url,thumbnail_url,children{id,media_url}", | ||
| "access_token": getToken(account), | ||
| } |
Comment on lines
35
to
+51
| media_url = request.GET.get("url") | ||
| # Present only on links generated by replace_media_urls_for_posts() — | ||
| # older/plain links (generate_token(url) alone) have none of these, and | ||
| # are verified and served exactly as before. | ||
| post_id = request.GET.get("post_id", "") | ||
| child_id = request.GET.get("child_id", "") | ||
| account = request.GET.get("account", "") | ||
|
|
||
| if not provided_hash or not media_url: | ||
| return HttpResponseBadRequest("Missing required parameters.") | ||
|
|
||
| expected_hash = generate_token(media_url) | ||
| if post_id: | ||
| expected_hash = generate_token_with_context( | ||
| media_url, post_id, child_id, account | ||
| ) | ||
| else: | ||
| expected_hash = generate_token(media_url) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
media_urlembedded on the WordPress side can already be expired by the time a visitor loads it — even though our own cache entry for that batch is still well within its 12h TTL.resolve_media_urlpreviously just returned a plain 400 with no way to recover. (Root cause originally diagnosed while fixing a stuck Instagram carousel on the frontpage — see the paired frontend fallback fix invvp_divi5_extensions.)generate_token_with_context()alongside the existing url-onlygenerate_token().resolve_media_urlnow does one retry: re-fetch that single post from Instagram (fetch_fresh_media_url, new) to get a freshly signed URL, then fetch that.id, which shouldn't happen but is technically optional in the API response) carry nopost_idand are verified/served exactly as before —generate_token(url)is unchanged,replace_media_urls()is unchanged and still directly tested.replace_media_urls_for_posts()is the new, additive, Instagram-feed-specific counterpart thatinstaFeednow uses instead.Test plan
python manage.py test proxycache— 68 tests pass (11 new, all existing ones untouched/still green)ruff check/ruff format --checkclean on all touched filesbandit -c pyproject.toml— no new findings (2 pre-existing low-severity findings ininsta_feed.py'sACCOUNTSdict are unrelated env-var-name string matches, not part of this diff)🤖 Generated with Claude Code