10분 지연 문제를 우회하는 방법 시도

골프 코스트 지역의 기상 예보 사이트에 wp-discourse 플러그인을 사용하려고 계획하고 있습니다. 이 사이트는 평소 하루 약 10,000~20,000페이지의 조회수를 기록하지만, 심한 기상 이벤트가 발생하면 하루 150만~200만 페이지 조회수에 약 50만~70만 명의 방문자가 몰리기도 합니다. 사이트와 호스팅 전략은 여러 번의 심한 기상 이벤트를 거치며 검증되었기 때문에, 정밀한 설계와 Cloudflare의 많은 도움 덕분에 압력 하에서도 훌륭하게 작동합니다.

사이트 사용자는 네이티브 워드프레스 댓글을 통한 저마찰(저장벽) 댓글 작성 경험에 익숙하므로, 일부 적응 과정(예: “…에서 토론을 계속하세요” 링크를 클릭하는 것에 익숙해지는 것 등)이 필요할 것입니다. 이는 사용자 응대 담당 직원이 관리할 준비가 되어 있습니다.

그러나 그들이 용납하지 못할 것은 댓글 게시와 일일 워드프레스 게시물 페이지에 댓글이 표시되는 사이의 가변적인 10분 지연입니다. 네이티브 WP 댓글이 게시 직후 즉시 표시되는 것과 유사하게, 새 댓글(설정된 한도 내에서)이 게시된 직후 홈페이지에 즉시 표시되기를 원합니다.

nginx의 fastcgi 캐싱, 워드프레스, 또는 브라우저 캐싱이 게시 후 새로고침 시 새 댓글이 표시되는 것을 방해하지 않도록 내장 옵션을 가지고 씨름한 끝에, 워드프레스 측에서 새로고침 시 새 게시된 댓글이 표시되도록 이 문제를 완화하기 위해 다음 두 개의 mu-plugin을 추가했습니다:

wp-discourse-transient-killer.php
wp-discourse-cache-header-fix.php

이로써 제 문제는 해결되었습니다: 워드프레스 생성의 Discourse 스레드에 새 게시물이 올라오면 이제 워드프레스 게시물 아래에 새로고침 시 즉시 표시됩니다.

하지만 여기서 제 역량 한계에 도달한 것 같습니다 — 이렇게 함으로써 무엇을 깨뜨리거나, 엉망으로 만들거나, 훼손하고 있을까요?

일일 기상 예보 페이지(임베디드 Discourse 댓글 포함)를 확인하는 방문자들이 댓글 엔드포인트를 마구 때려내어 웹호스트에 추가 부하를 주는 것에 대해서는 특별히 신경 쓰지 않습니다. 이는 돈을 들여 해결할 수 있는 문제입니다. 제 1차 요구사항은 20,000명 이상의 사용자가 댓글을 게시했는데 왜 홈페이지에 즉시 표시되지 않느냐고 이메일을 보내는 것을 피하는 것입니다.

이것이 올바른 접근 방식인가요? 제가 하는 일이 현명한가요? 예상하지 못한 추가적인 보안이나 성능 문제를 발생시키나요? 기본적으로, 이렇게 해서 일을 망치고 있는 건가요?

감사합니다 :slight_smile:

음, 이게 왜 동작하는지 혼란스럽네요.

그리고 당신의 플러그인은 다음과 같습니다.

add_action( 'wpdc_after_webhook_post_update', function( $topic_ids ) {
    foreach ( (array)$topic_ids as $topic_id ) {
        delete_transient( 'wpdc_comment_html_' . $topic_id );
    }
}, 11 );

액션으로 전달되는 (워드프레스) $post_id와 트랜지언트 키로 사용되는 (디스커스) topic_id를 혼동하고 있는 것은 아닌가요?

플러그인은 다음과 같이 작성되어야 한다고 기대할 것 같습니다.

add_action( 'wpdc_after_webhook_post_update', function( $post_ids) {
    foreach ( (array)$post_ids as $post_id ) {
        $topic_id = get_post_meta( $post_id, 'discourse_topic_id', true );
        delete_transient( 'wpdc_comment_html_' . $topic_id );
    }
}, 11 );

하지만 당신은 이것이 동작한다고 말하고 있네요? :thinking:

안녕하세요 @Lee_Ars, 먼저 댓글 웹훅 설정이 되어 있는지 확인해 주시겠어요?

동작 방식은 다음과 같습니다:

  1. Discourse에 새 게시물이 생성됩니다.
  2. 웹훅 페이로드가 Wordpress로 전송됩니다.
  3. WP discourse가 게시물에서 댓글 수를 업데이트하고, 게시물 커스텀 필드 wpdc_sync_post_comments도 설정합니다.
  4. wpdc_sync_post_comments가 설정되어 있으면, 동기화 주기(예: 10분 지연)와 관계없이 Wordpress 게시물이 로드될 때 Discourse 댓글이 동기화됩니다.

캐싱 문제를 다루기 전에, 먼저 이 설정이 제대로 되어 있는지 확인하고 싶습니다. 만약 설정되어 있다면, "Verbose Webhook Logs"를 활성화하여 Discourse에서 새 게시물이 생성될 때 웹훅 요청을 수신하고 있는지 검증해 보시는 것도 좋습니다.

안녕하세요 Angus! 네, 확인했습니다. WP 쪽에서는 “Sync Comment Data” 웹훅 옵션이 활성화되어 있고, Discourse 쪽에서도 웹훅을 생성했으며 핑(ping)도 성공적으로 전송되고 있습니다. WP 플러그인의 로그에는 적절한 타임스탬프에 comment.INFO: sync_comments.success 메시지가 표시되고 있습니다:

[2025-07-07 14:16:38] connection.INFO: check_connection_status.successful_connection  
[2025-07-07 14:16:38] connection.INFO: check_connection_status.valid_scopes  
[2025-07-07 20:11:31] comment.INFO: sync_comments.success {"post_id":786} 
[2025-07-07 20:25:03] comment.INFO: sync_comments.success {"post_id":786} 
[2025-07-07 20:32:14] comment.INFO: sync_comments.success {"post_id":786} 
[2025-07-07 20:44:15] comment.INFO: sync_comments.success {"post_id":786} 
[2025-07-07 21:00:39] comment.INFO: sync_comments.success {"post_id":786} 
[2025-07-07 21:01:42] comment.INFO: sync_comments.success {"post_id":786} 
[2025-07-07 21:15:40] comment.INFO: sync_comments.success {"post_id":786} 

문제는 이러한 성공 메시지가 있음에도 불구하고, 기존 방문자(적어도 저의 경우, Mac에서 Firefox/Safari/Chrome, Win10 PC에서 Firefox/Chrome/Edge, iOS에서 Safari를 여러 번 테스트했는데)들이 cache-control 헤더가 0이 아닌 값으로 설정된 캐시된 /wp-json/wp-discourse/v1/discourse-comments 엔드포인트를 계속 받아보고 있다는 점입니다. Chrome에서 Ctrl+Shift+F5(또는 다른 브라우저의 동등한 단축키)를 눌러 로컬 캐시를 우회하고 새로고침을 강제하면, 모든 것이 정상 작동하며 새 게시물이 표시됩니다.

mu-plugins가 설치된 상태에서는 해당 엔드포인트의 cache-controlno-store no-cache 등으로 설정되어 있고, 문제 행동이 나타나지 않습니다—단순히 WP 게시물을 방문하거나 일반 새로고침 버튼으로 새로고침해도 새로운 임베드된 댓글이 표시됩니다.

상세한 웹훅 로그를 켜고 테스트 게시물을 작성했는데, 새 게시물을 만들 때 모든 것이 정상으로 보입니다:

webhook_topic.INFO: update_topic_content.update_post_metadata_success {"post_ids":"786"}

모든 것이 작동하는 것처럼 보이지만, 여전히 원래 문제 행동이 왜 나타났는지, 아니면 제 쪽에서 간과한 어떤 문제에서 비롯된 것인지 정확히 이해하지는 못합니다. (매우 가능성이 높습니다!)

아, 죄송합니다. 제가 그 부분을 실수한 것 같다는 말씀에 동의합니다. 어제는 긴 하루였고, 말씀드린 것처럼 제 능력의 한계 근처에 있는 상태입니다. 분명히 _무언가_는 하고 있었지만, 이제 제가 보고 있는 “수정된” 행동이 단순히 새로운 방식으로 깨져 있는 것인지 궁금해집니다. (이제 “transient killer” 플러그인을 올바른 인수를 사용하도록 업데이트했습니다. 감사합니다!)

감사합니다. 한 가지 더 확인하고 싶은 것이 있습니다. 이 WP Discourse 설정(“Commenting” 항목)이 켜져 있나요?

Cache Comment HTML 설정을 활성화하거나 비활성화한 경우 모두 시도해 보았는데, 문제 동작에 아무런 영향을 미치지 않는 것 같습니다. 현재는 비활성화 활성화 상태입니다(죄송합니다. 제가 잘못 말씀했네요. 계속 확인해 보고 있는 중이라 현재는 활성화되어 있습니다). 문제 해결에 도움이 된다면 설정을 어떻게든 변경할 수 있습니다.

설정이 비활성화되어 있으면 해당 플러그인이 아무 동작도 하지 않기 때문에 topic_id / post_id 혼동을 알아차리지 못할 수 있습니다. 캐싱이 없으므로 잘못된 캐시를 삭제해도 문제가 되지 않습니다.

설정이 활성화되어 있으면 플러그인이 제대로 작동하지 않는 것을 알아차릴 수 있어야 합니다.

즉, 문제를 해결하려면 설정을 활성화해야 합니다.

네, 귀하의 경우를 위해 첫 번째 조치로 다음을 제안합니다:

  1. 캐시 댓글 HTML(Cache Comment HTML)을 비활성화 상태로 유지하고;
  2. Richard가 지적한 바와 같이 현재 아무런 역할을 하지 못하고 있는 https://www.bigdinosaur.org/r/wp-discourse-transient-killer.txt 플러그인을 제거하세요.

이 조치로 문제가 해결되지 않는다면, 문제는 다른 형태의 캐싱과 관련이 있을 것입니다. 다음 질문에 답해야 합니다:

  1. 귀하(그리고/또는 호스팅 제공업체)는 WordPress에 어떤 캐싱 솔루션을 사용하나요?
  2. https://www.bigdinosaur.org/r/wp-discourse-cache-header-fix.txt 가 문제를 해결한다면, 이 플러그인의 특정 동작은 1번에서 적용 중인 캐시를 어떻게 무효화(invalidate)하나요?

wp-discourse-cache-header-fix를 살펴보니, 수정 사항 중 하나가 load-comments.js와 관련된 것으로 보입니다. 이 설정이 활성화되어 있나요?

nginx + php-fpm 8.3 환경에서 자체 호스팅된 WP를 사용 중입니다. 동적 콘텐츠에는 nginx fast-cgi 캐싱을, 객체 캐싱에는 Redis를 사용하며(객체 캐시 드롭인이 활성화됨) 다른 레이어(CDN, CF, nginx fast-cgi 캐시 외에 서버 내 Varnish 또는 기타 로컬 캐시)는 없습니다. nginx fast cgi 캐시를 강제로 비우는 작업(rm -rf /etc/nginx/cache/* 실행)은 문제의 동작에 영향을 미치지 않습니다 — 캐시 디렉토리를 삭제하고 nginx와 php-fpm을 모두 재시작해도 여전히 오래된 결과가 제공됩니다.

실제로 현재 Ajax 댓글 로딩이 활성화되어 있지만, 이를 끄고(혹시 모를 경우를 대비해 nginx 캐시 비우기 및 nginx와 php-fpm 재시작 포함)도 문제의 동작에는 변화가 없었습니다. 브라우저가 여전히 오래된 댓글을 가져오기 때문입니다.

옵션을 전환하고 transient-killer를 제거했습니다. 문제의 동작에는 변화가 없습니다.

이 플러그인이 적용하는 효과는 캐시 시간을 지정하는 헤더 대신 no-cache cache-control 헤더를 제공하는 것으로 보입니다. 이 플러그인이 없으면 브라우저는 wp-json/wp-discourse/v1/discourse-comments 엔드포인트의 오래된 캐시 버전을 디스크 캐시에서 제공하려는 경향이 매우 강합니다. 언급했듯이, no-cache 새로고침을 강제하려면 shift-ctrl-f5(또는 동등한 단축키)를 사용해야 합니다.

문제 동작은 영구적인 서버 측 캐시가 아니라 브라우저 측에 있는 것 같습니다. 제가 접근할 수 있는 모든 OS의 모든 브라우저에서 동일한 현상이 일어나고 있기 때문입니다.

좋아요, 100% 명확하게 확인하기 위해 이렇게요:

  • 정상 작동하는 댓글 웹훅
  • 캐시된 댓글 HTML 끔
  • AJAX 로딩 끔
  • CDN 없음
  • CloudFront 없음
  • WordPress 캐싱 플러그인 없음
  • PHP 로그에 관련 경고나 오류 없음

이런 상태에서 정말로 작동하지 않는다고 확신하나요?

이 설정으로 작동하지 않는다면, 직접 자세히 살펴볼 수 없는 상황에서는 제가 좀 막막합니다. 그래서 기본적으로 다음 설정을 제안하게 됩니다:

  • AJAX 로딩 켬
  • wp-discourse-cache-header-fix.php 수정 사항 적용

제가 추측하건대, 이게 원래 작동했던 설정이었을 겁니다. 이 경로가 작동한다면, 이 방법을 사용하는 것이 좋습니다.

참고로, 현재 플러그인 설정의 스크린샷을 담은 간단한 imgur 갤러리를 첨부합니다.

CDN, Cloudfront, Cloudflare 모두 없으며, Nginx 헬퍼를 제외하고는 캐싱 플러그인이 없습니다. (Nginx 헬퍼는 필요할 때 WP가 nginx fast-cgi 캐시를 무효화하는 데 도움을 주기 위해 사용하는 것입니다.)

또한 php-fpm이나 nginx 오류 로그에 관련된 내용이 전혀 없음을 확인합니다.

아, 정말 작동하길 바랐는데. 잠깐씩 자면서 이 문제로 약 30시간째 머리를 쥐어박고 있습니다. 이제 눈이 조금 빙글빙글 도는 것 같네요, 헤헤.

응, 공감해. 하루 정도는 쉬어. 내일 너의 설정을 그대로 복제해서 문제를 재현해볼게.

해결책을 찾지 못하고 헤매게 된다면, 그리고 원하신다면, 문제를 해결하기 위해 내일이나 그 다음 날 WP 블로그, 디스커스, 그리고/또는 기반 호스트에 대한 임시 로컬 접근 권한을 부여할 수 있습니다. 물론 무상 노동을 받으려는 것은 절대 아닙니다. 실제로 시간이 소요된다면 서비스 비용을 기꺼이 지불하겠습니다.

참고로, 워드프레스를 호스팅하는 서버와 디스코드를 실행하는 서버 모두 AWS의 Ubuntu 24.04 AMI를 실행하는 t3a.large EC2 인스턴스입니다. 설치된 소프트웨어는 최소한으로 유지되고 있습니다(웹 호스트에는 nginx + php8 + fpm + redis, 디스커스 호스트에는 git + docker + discourse 이상). 이는 제 개인 블로그이며, OP에서 언급된 훨씬 더 큰 규모의 WP 사이트에서 프로덕션으로 배포하기 전에 여기서 댓글 통합을 테스트하고 있습니다. (저는 그 사이트도 관리하고 있으며 유사한 기술 스택을 사용하지만, Cloudflare가 프론트엔드에 위치해 있습니다. 그 부분은 때가 되면 다룰 것입니다!)

기반 스택에 대한 추가적인 세부 사항이 필요하거나 원하신다면, 기꺼이 제공하겠습니다.

좋아요, 제 문제를 재현해 보려다(실패하고) 만든 영상이에요:

다음으로 시도해 보길 원하는 것은 이 필터입니다.

@angus 감사합니다 — 실제로 재현이 안 되는 것이 오히려 훨씬 마음이 놓입니다. 왜냐하면 실제로 문제가 있는 것이 아니라 제가 무언가를 잘못하고 있다는 뜻이니까요 :smiley:

오늘 디버깅할 시간을 확보해서 해당 필터를 추가하고 다시 보고드리겠습니다 :+1:

한 달여 뒤에야 답글을 올려서 마무리합니다. 여전히 전체 프로덕션 배포 시 이상한 현상들이 발생하고 있습니다 (prod 사이트, 디스커스 임베드가 포함된 예시 프로덕션 사이트 게시물, 실제 디스커스 포럼) 하지만 모두 관리 가능한 수준입니다. 남은 지연/지체 문제는 워드프레스 + 디스커스 + 클라우드플레어로 이루어진 복잡한 레이어 케이크와, 실제 폭풍으로 인한 트래픽 폭증 시 모든 시스템이 운영될 수 있도록 유지하기 위한 제 공격적인 캐싱 전략 탓으로 돌리겠습니다.

시간 내어 답글을 남겨주셔서 감사합니다, @angus <3

다시 한번 이 글을 올려 죄송합니다. 다만, 문제의 원인을 찾았으니 후속 보고를 하고 싶었습니다. 그리고 그 원인은 역시 제 실수였습니다.

간단히 말씀드리면, 저는 /etc/nginx/snippets/ 아래에 일반적인 PHP location 블록 세부 정보를 스니펫으로 관리하고 있습니다. 이렇게 하면 여러 vhost 파일에서 이를 포함할 때 매번 중복해서 작성할 필요가 없기 때문입니다. 이 스니펫을 확인한 지 아주 오래(아마도 수년)되었는데, 예상대로 add_header Cache-Control "public, max-age=7200";라는 불필요한 설정이 남아 있었습니다. 이 설정은 해당 location 블록을 통해 나가는 모든 요청에 적용되고 있었습니다.

그래서 해당 설정을 제거하고 모든 캐시 계층을 비웠더니, 정말로 문제 증상이 사라졌습니다.

@angus 님, 제 실수로 인한 또 다른 Discourse 문제였음에도 불구하고 시간을 내어 도움을 주셔서 다시 한번 감사드립니다. :people_hugging: