Команда GitHub Issues значительно ускорила работу сервиса за счёт перехода к клиентскому кешированию и модели «local-first». Теперь страницы задач отображаются почти мгновенно, а обновление данных происходит в фоне.
Разработчики отмечают, что при работе с большим количеством задач задержки при переходах воспринимаются как потеря контекста и напрямую влияют на качество продукта. GitHub Issues использует метрику HPC (Highest Priority Content), близкую к LCP в Web Vitals, чтобы измерять момент появления ключевого контента страницы, например заголовка или тела задачи.
Ранее многие переходы к просмотру задач issues#show выполнялись как «жёсткие» навигации с полной перезагрузкой страницы, особенно при переходах между страницами на Rails и React. Это приводило к холодному старту клиента, лишним сетевым запросам и повторному рендерингу.
Чтобы изменить ситуацию, команда сместила акцент с единичных оптимизаций бэкенда на архитектуру загрузки страниц. Целью стало добиться, чтобы как можно больше навигаций укладывалось в менее 200 мс и воспринималось пользователями как мгновенные, а «быстрый» сценарий стал основным для большинства сессий.
Первый шаг — кеширование данных задач на клиенте. Поверх существующего in-memory хранилища GitHub внедрил постоянный кеш в IndexedDB и реализовал стратегию stale-while-revalidate: страница рендерится сразу из локальных данных, а проверка свежести и обновление выполняются асинхронно.
После запуска кеша примерно 22% навигаций через React стали мгновенными вместо 4% до изменений, что затронуло около 15% всего трафика issues#show. Доля попаданий в кеш достигла ~33%, при этом расхождение между кешом и сервером держится на уровне около 4,7% и контролируется как допустимый компромисс ради снижения задержки.
Дальнейшая оптимизация была направлена на рост доли попаданий в кеш за счёт «разогрева» (preheating). На страницах с высоким намерением перехода (списки задач, дашборды, проекты, представления зависимостей) GitHub заранее подготавливает записи в кеше, но делает сетевой запрос только если данных ещё нет.
В отличие от агрессивного prefetch, разогрев не навязывает обновление свежих данных для всех возможных переходов. Это логика заполнения кеша: если в локальном кеше уже есть пригодная информация, дополнительные запросы не отправляются. Такой подход экономит ресурсы и отдаёт приоритет запросам пользователей, а фоновые операции ограничиваются по частоте и отключаются при нагрузке с помощью «предохранителей».
Чтобы быстрее обслуживать «горячие» задачи, перед IndexedDB добавили ещё один слой — in-memory кеш, который позволяет отдавать популярные записи синхронно, без дополнительной асинхронной операции чтения из IndexedDB. Это ещё больше уменьшило время до первого рендера при мягких навигациях.
После широкого запуска разогрева доля мгновенных переходов к issues#show выросла примерно до 30% для всех навигаций. Для переходов через React до 70% таких переходов стали мгновенными, а попадания в кеш приблизились к 96%.
Отдельное внимание команда уделила «жёстким» навигациям: обновление страницы, открытие в новой вкладке, переходы по прямым ссылкам. Здесь ключевую роль сыграл service worker, который перехватывает запросы навигации до сервера и проверяет наличие данных задачи в локальном кеше.
Если данные уже кешированы, service worker добавляет к запросу на сервер специальный заголовок. Это позволяет серверу пропустить часть работы по формированию ответа и вернуть более лёгкий вариант страницы, опираясь на уже имеющиеся у клиента данные. При отсутствии кеша или service worker система возвращается к стандартному SSR-сценарию.
Этот подход особенно хорошо сработал для навигаций на базе Turbo, которые сильно зависят от времени ответа сервера. При наличии сигнала о готовых данных сервер тратит меньше ресурсов на генерацию фрагментов, а Turbo ускоряет переходы почти сразу.
Однако на «жёстких» навигациях при попадании в кеш узким местом становится уже не сервер, а загрузка и выполнение JavaScript. Для снижения этой нагрузки GitHub реализовал разделение кода по маршрутам с помощью React.lazy и динамической подгрузки: загружается только код для текущей страницы, а второстепенные модули подгружаются при необходимости.
Компоненты, не влияющие на начальный рендер, откладываются. Например, пакет с редактором задачи загружается только в момент перехода в режим редактирования, а для сглаживания задержки используется подгрузка по намерению (например, по наведению курсора).
Суммарный эффект команда оценивает по динамике HPC на всём промежутке внедрения: от кеширования в IndexedDB и разогрева до введения in-memory слоя и service worker. Низкие перцентили (P10, P25) заметно улучшились за счёт доминирования кешированных и разогретых навигаций, медиана также стала лучше, но всё ещё зависит от холодных стартов.
Верхняя часть распределения отражает сценарии, где остаётся зависимость от SSR и тяжёлого запуска клиента: это следующий приоритет. GitHub планирует целевые переработки частей бэкенда с фокусом на минимальные задержки и развёртывание нового слоя доставки UI ближе к edge-инфраструктуре для сокращения сетевых раунд-трипов.
В компании подчёркивают, что работа над производительностью GitHub Issues — это длительный системный процесс. Архитектура меняется, узкие места смещаются, но цель остаётся прежней: сделать быстрый отклик стандартом для всех сценариев навигации в задачах.
Источник: инженерный блог GitHub.






















