With Discourses 1RTT philosophy, I think it might be time to rewrite the Avatar image serving code.
Avatar images should be treated as any other image upload. Resized at upload, stored, and served directly from the file system/S3/CDN.
The current Discourse method uses a proxy method to serve Avatar images. This approach creates unnecessary HTTP round trips and IP address challenges.
Here is an overview of Avatar Requests:
Initial Discourse HTML is painted.
Browser detects an avatar image and requests an image from the Discourse server
Discourse server acts as a proxy and requests the image from local file store/S3/CDN
Discourse server receives image
Discourse server sends the image to the browser.
Every custom avatar has 1 additional HTTP roundtrip and related server processing time. A typical topic or topic listing can have 30 plus custom avatar images. On my site, that results in 10K to 20K extra RTT and related server load per day that could be avoided.
Additionally, the avatar images are direct access called from the server. To do any CDN-level protection requires whitelisting the IP address. This requires whitelisting gateways versus server IP addresses. Hosting companies make changes to balance network traffic on a regular basis. My gateway IP address will change/evolve. The software should not depend on updating the IP address for basic avatar images to work. This is based on the following incident in support, Avatar Proxy and CDN Hot-Link Protection
From a performance and simplicity perspective, can we have avatar images served directly from the Discourse’s designated file store?
This is indeed a very convoluted part of the app @LotusJeff.
To address some of it’s shortcomings, we recently developed a way to reduce those round trips in our hosting, but I don’t think we ever documented it here. Is there any public docs about it @david ?
Yeah, we have this GlobalSetting, which you can enable by setting the environment variable DISCOURSE_REDIRECT_AVATAR_REQUESTS=true
Then, instead of proxying, avatar requests will be served with a 302 redirect to the file store.
By itself… that’s not really a good idea. It means browsers have to make two full HTTP roundtrips for every avatar. So, while it might solve your ‘hotlinking protection’ problem… I wouldn’t recommend that you enable it. It will make the experience worse for your users.
We use the setting on our discourse.org hosting. But we supplement it with a lambda running on our Cloudfront CDN. It detects the 302 and performs the proxying itself. Essentially: we move the proxying from our application servers to the CDN.
As for the more general question of “can we change avatars to link directly to the asset”. It’s tricky because avatar URLs are baked into all historic posts (e.g. quotes). The dynamic /user-avatar/ URLs allow us to keep those working when a user changes their avatar. I’m afraid we don’t have any plans to change that system.
If there’s an easy low-risk way we could make the existing proxying work for your use-case (e.g. add a GlobalSetting which inserts a specific HTTP header in any avatar-proxy requests), then we could consider accepting a PR for the change.
אף אחת מהאפשרויות שהוזכרו לעיל אינה מעשית או מועדפת בסביבתי הנוכחית. הייתי שמח לעזור לפתרון החלק המסובך הזה של היישום, אבל אני חדש מאוד בטכנולוגיה זו.
העזרה היחידה שאני יכול לספק עכשיו היא באמצעות הכישורים הישנים שלי ב-BA ובניהול פיתוח. אז, ברוח כך שאני מרגיש שאני תורם, אלו המחשבות שלי.
כאשר אני מסתכל על כל בעיה טכנית, אני מתחיל תמיד בבחינה של הנחות אפשריות שהיו מקשות על פתרון.
הנחה אחת היא לשמור תמונת אבטר מעודכנת בשם קובץ חדש. האדם שיש לו אבטר אחד בלבד. אנחנו לא שומרים רישום של שמות האבטרים. אני מציע שכאשר מישהו מעדכן את תמונת האבטר שלו, היא יתאחסן באותו שם קובץ של האבטר הקיים. זה בעצם מה ש- /user-avatar/ עושה. במקום עבודהית, תבצע את לוגיקת זו בזמן יצירת / עדכון האבטר. זה יפתור את החשש מכתבות היסטוריות לפוסטים עתידיים.
האם זו שינוי של מהפך גדול? לא, שינוי זה יכול להתבצע במשך חודשים, תוך שיפור הדרגתי בביצועי האתר. צוותי הפיתוח שלי תמיד היו עם רשימת קוד הזדמנות לקוד בכל בלוק קוד. רצינו לבצע שיפורים אלו, ولكن הם לא היו קריטיים לביצוע באופן אישי. כאשר הקוד נפתח לפיתוח מסיבה אחרת, המפתח גם ביצע שינויים הזדמנותיים. זה הקטין את הצורך בבדיקות ותקלות על ידי הפחתת הפעמים שהקוד נפתח ועדכון.
אני אציע לחלק את הפרויקט למספר שלבים:
עדכון לוגיקת שמירת תמונת אבטר כדי להחליף כל עדכון תמונה באמצעות שם קובץ נוכחי.
החלפת כל השימושים בתמונות אבטר עם פונקציה סטנדרטית שמשתמשת במערכת אחסון/הגשה המועדפת של discourse. אלה יכולים להיות מיושמים בהדרגה, תוך מעבר הדרגתי ללוגיקת הצגת התמונות של האבטר החדשה.
לאחר שהשלב הראשון והשני הושלמו, לספק לקהילה את המדריכים וקטעי הקוד כדי להחליף ולהוציא את התמונות ההיסטוריות מתוך HTML חומצה ולהעביר אותן למערכת הקבצים המועדפת. זה יהיה באחריות של בעלי אתרי discourse לבחור לבצע זאת. (מדריכים וקטעי קוד אלו יהיו שימושיים לביצוע שינויים ב-HTML הגולמי)
אני בטוח ששיקלת את כל זה. אני גם יודע ששיפוץ קוד ישן תמיד אינו בראש סדר העדיפויות.
אם יש משהו שאני יכול לעשות כדי לסייע במאמץ הזה, אנא יידע אותי.
נ.ב. אני מעריך את ההצעה של יצירת חיבור ברירת מחדל לכותר הגלובלי. אשקול מחקר נוסף ואמשיך עם דרישות מוגדרות יותר. תודה על העזרה שלך.
Unfortunately if the file is mutable, it would mean we can no longer enable infinite caching of the asset in the CDN and end-user browsers.
There are strategies to make something like that work without hurting performance too much… e.g. the stale-while-revalidate directive. But that brings its own costs & UX implications.