본문 바로가기

Org Publish가 이맥스를 자꾸 얼리고 있어요

기술적인 이야기/이맥스 2020. 1. 10.
반응형

앞서 Org Publish에 관한 글을 썼습니다. 매우 편하게 Org Mode 글들을 자동으로 익스포트 해주는 고맙고 편한 도구이지요. 그런데 글들을 익스포트 하기 위해 org-publish-all 등의 함수를 사용하면 간혹 이맥스가 꽁꽁 얼어버립니다. 반응도 없이 마치 죽은 것처럼 말이죠.

이 글은 이 문제를 해결하기 위한 사투를 간단하게(?) 정리하는 글입니다.

긴 글을 읽고 싶지 않으시다면 가장 마지막의 '대안' 항목을 읽어보세요.

문제를 찾아보려 했으나

증상을 정확히 정의하자면, 글을 편집하고 나서 org-publish 혹은 org-publisha-all 함수를 사용해 업데이트 한 글을 자동으로 퍼블리시를 시도하는데 이때 특정 확률로 이맥스가 멈춰 버리고 커서가 바람개비 뺑뺑이로 표시되고 CPU 사용량이 과도하게 올라갑니다. 덤으로 맥북은 이륙하고요. 마치 버그로 무한루프를 도는 제 앱을 보는 것 같습니다.😭

그렇다면 이걸 디버깅 할 수 있는 방법이 있어야 합니다. 관련된 정보를 찾아보면 SIGUSR2 시그널을 이용해 이맥스의 얼어붙은 상태를 해소할 수 있다고 합니다. 이 시그널을 보낼 수 있는 여러 방법이 있겠지만, macOS에서는 아래 커맨드가 가장 간단하더군요

pkill -SIGUSR2 Emacs

자 이렇게 하면 이맥스에서 루프 지점에 트레이스가 걸리면서 디버그 모드로 진입을 해야 합니다.

그런데 제 맥에서는 전혀 반응이 없습니다. 심지어 재미있는 점은 멈춰있는 이맥스 윈도를 클릭하면 이맥스 창이 꺼저버리더군요. 참 난감합니다.

이 외에 debug-on-quit 값을 이용하는 방법도 있다길래 시험해 봤습니다. 아래의 커맨드로 디버그 모드를 켜줍니다.

(setq debug-on-quit t)

이 상태로 C-g 키를 누르면 실해 중인 코드에 브레이크가 걸리게 됩니다.

하지만 이게 되었다면 아마 이 글을 쓰는 게 아니라 버그 이슈를 쓰고 있었겠지요. 네. 전혀 도움이 안 되었습니다.

결과적으로 이 문제는 Emacs의 구현체인 C 코드로 작성된 코어 부분의 버그로 보는 것이 합당해 보입니다. 그런데 이걸 디버깅하려면 일단 이맥스를 디버그 모드로 빌드한 후 멈추는 지점을 미리 파악하고 디버거로 브레이크를 걸어야 하지요. 애초에 코드를 읽어보지 않은 저에겐 매우 오래 걸리고 힘들고 피곤하고 지치고 어려운 일입니다.

우연히 발견한 원인스러운 원인

이 문제를 해결하기 위해 온갖 짓(?)을 시도해 봤습니다만 차도가 없었습니다. 원인도 몰랐습니다. 할 수 없이 애처롭게 Messages 버퍼를 표시한 채로 Publish를 자주 시도해 봤습니다. 뭔가 오류 메시지라도 표시되나 해서요.

그런데 신기한 일이 발생합니다. Messages 버퍼를 전면에 띄워둔 상태에서는 이맥스가 죽지 않더군요. 🤔

...?

네. 저는 우연히 이맥스를 프리징 시키는 조건(?)을 찾은 것 같습니다.

정확하게 분석하기는 힘듭니다만, 추측으로 표현하자면 아래와 같이 정리할 수 있습니다.

편집한 Org 글을 그대로 전면(focus)에 둔 상태에서 Publish를 할 경우 낮을 확률로 프리징이 발생합니다.

즉 Messages 버퍼와는 관계가 없습니다만 이 버퍼 덕분에 원인스러운 것을 찾았다는 말이지요. 참 어이가 없네요. 그래도 이 정도면 해결법을 찾을 수 있을 것 같았기에 마냥 기쁘기만 했습니다.

자 그럼 해결해보죠.

대안

사실 앞서 이야기했지만, 이맥스의 코어 부분이 문제이므로 이 문제를 원천적으로 해결할 수는 없습니다. 대신, 포커스를 돌려서(?) 익스포트를 시도하면 문제가 없다는 것을 알았으니 이걸 자동화하면 됩니다.

아래와 같은 코드를 하나 작성했습니다.

(defun publish-seorenn-web ()
  (interactive)
  (switch-to-buffer "*Messages*")
  (goto-char (point-max))
  (run-at-time 1 nil (lambda ()
                       (message "Start publish")
                       (org-publish-all)
                       (message "Finished to publish"))))

단순하게 Messages 버퍼를 표시하고, 이 버퍼의 하단으로 커서를 옮기고, 약 1초 후 비동기로 org-publish-all 함수를 호출하도록 한 코드입니다. 왜 1초 비동기로 했냐 하면, 이렇게 하지 않으면 Messages 버퍼가 보이기도 전에 Publish가 끝나버려서 왠지 불안했기 때문입니다.

어쩔 수 없었던 불가피한 선택

어쨌든 이제 org-publish 함수 대신 이 publish-seorenn-web 함수를 이용하니 한 달 넘도록 문제가 재현되지 않았습니다. 뭐 거의 확실한 원인을 찾았다는 말이 되겠네요.

728x90
반응형

댓글