사용자 디렉터리에서 사용자 통계가 잘못 표시됩니다

해당 브랜치를 기반으로 빌드된 Codespace에서 재현할 수 있었던 것 같습니다.

오늘 사용자 디렉터리에서 숫자가 때때로 잘못 표시되는 것을 발견했는데, 사용자가 로드되지 않는 문제 때문일 것 같아서 시도해 보았습니다.

잘못된 숫자의 예시:


사용자 디렉터리를 열었을 때의 모습입니다. 시간 범위는 주간, 정렬 기준은 받은 좋아요 수입니다. 이제 정렬 기준을 읽은 게시글 수로 변경하면:

이어서 시간 범위를 오늘로 변경하면:

그리고 새로고침 후에도 동일한 상태(오늘, 읽은 게시글 수 순서)입니다.

보시는 바와 같이, 새로고침 후 @lcor가 오늘 읽은 게시글 수가 변경되었습니다. 이전에는 정렬된 목록에 맞지 않는 상태였습니다.
사실 214는 이번 주에 읽은 게시글 수입니다:


이 절차를 수행했을 때 오늘 수치가 아닌 주간 수치가 표시된 계정은 이 하나뿐이 아니었습니다. 실제로는 주간 수치가 표시되고 있음에도 불구하고, 위치가 잘못되어 보이는 사용자가 더 있습니다.

새로고침 전/후 목록의 다음 사용자들

이것이 동일한 문제라고 보시나요, 아니면 우연히 지금 두 가지 문제가 있는 건가요?

4개의 좋아요

두 가지 문제였습니다. 다른 하나는 수정되었습니다.

아래 단계로 여전히 재현할 수 있습니다. 예를 들어, 재로드 전에는 thoka의 통계가 잘못되어 있습니다:

재로드 후에는 올바르게 표시됩니다:

메타 환경에서 재현할 수 있습니다

새로고침 전

새로고침 후

숫자가 실제로는 다릅니다. 하지만 더 중요한 것은 directory_items 엔드포인트에 항상 두 번의 요청(하나는 .json 확장자가 있고, 다른 하나는 없는 경우)이 이루어진다는 점인데, 그중 하나가 잘못된 파라미터를 가지고 있습니다 :thinking:

다만 로컬에서는 재현하지 못했습니다. 두 개의 다른 요청이 있긴 하지만, 엔드포인트가 다릅니다 (groups/search.jsondirectory_items)

수정: user card directory 테마 구성 요소를 활성화해도 문제/동작은 변하지 않습니다.

1개의 좋아요

로컬 설치에 사용자를 더 추가해 보셨나요? 50명 이상의 사용자가 필요해서 모든 사용자가 한 번에 로드되지 않는 것이 아닌가 싶습니다.
잘못된 숫자가 표시되던 사용자는 처음 로드될 때 화면에 보이지 않던 사용자였던 것 같습니다.

불필요한 요청이 정렬 순서/열 변경 시마다 발생하지 않도록 데이터를 로컬에 캐싱해 보았습니다.

하지만 로컬에서 재현할 수 없었기 때문에, 프로덕션에서 발생하는 이중 요청/레이스 컨디션 문제를 해결할 수 있을지 확실하지 않습니다 :frowning:

2개의 좋아요

음, 이중 요청 문제가 해결되지 않았고, 이제 undefined에서 "loadMore"가 호출된다는 JS 오류가 나타납니다 :thinking:

1개의 좋아요

결국 이것은 “load more” 동작을 트리거해야 할 시점을 감지하는 데 사용하는 "sentinel"과 사용자 디렉터리 행 렌더링 사이에 발생한 까다로운 "경쟁 조건(race condition)"이었습니다 :exploding_head:

문제

최소 50명의 사용자가 있을 때, /u(사용자 디렉터리) 페이지가 사용자가 아래로 스크롤하기도 전에 첫 로드 시점에 즉시 loadMore를 트리거했습니다. 이로 인해 원치 않는 두 번째 페이지의 결과가 자동으로 로드되었습니다.

근본 원인

초기 페이지 로드 시 타이밍 경쟁 조건:

  1. 사용자가 /u로 이동합니다.
  2. controllers/users가 데이터 로드를 시작합니다 (isLoading: true).
  3. 스피너가 표시되는 ConditionalLoadingSpinner와 함께 템플릿이 렌더링됩니다.
  4. 데이터가 도착하고 isLoadingfalse가 됩니다.
  5. 스피너가 숨겨지고 DirectoryTable이 50명의 사용자를 렌더링하기 시작합니다.
  6. LoadMore sentinel 요소가 DOM에 삽입됩니다.
  7. IntersectionObserver가 생성되고 즉시 관찰을 시작합니다.
  8. 이 시점에서 테이블은 여전히 레이아웃을 계산하고 있으며 전체 높이로 확장되는 중입니다.
  9. 테이블이 확장되기 전, sentinel이 뷰포트에서 잠시 동안 가시 상태가 됩니다(상단에서 약 292px 위치).
  10. Observer가 교차를 감지하여 loadMore를 트리거합니다 :cross_mark:
  11. 테이블이 최종 높이(약 3689px)로 확장됩니다.
  12. Sentinel이 올바른 위치(뷰포트 아래, 약 3959px)로 이동합니다.

Observer가 "너무 성급"했습니다 - 콘텐츠가 레이아웃을 완료하기 전에 관찰을 시작하여, 테이블이 최종 높이에 도달하지 않은 짧은 순간에 sentinel을 감지했습니다.

해결 방법

콘텐츠가 준비될 때까지 Observer 생성을 지연시킵니다:

콘텐츠가 여전히 로드 중일 때 IntersectionObserver가 생성되지 않도록 방지하는 @isLoading 파라미터를 LoadMore에 추가했습니다.

현재 작동 방식

페이지 로드 → isLoading=true → Modifier가 Observer 생성을 건너뜀
             ↓
데이터 로드 완료 → isLoading=false → Modifier가 재실행되어 Observer 생성
             ↓
테이블이 완전히 확장됨 → Sentinel이 올바른 위치(뷰포트 아래)에 위치
             ↓
사용자가 아래로 스크롤 → Sentinel이 뷰포트에 진입 → loadMore 트리거 ✓

5개의 좋아요

이 주제는 15시간 후 자동으로 닫혔습니다. 새로운 답변은 더 이상 허용되지 않습니다.