Rack 애플리케이션을 위한 코드 리로딩 구현

Code Reloading for Rack Apps | Jared Norman

작성자
발행일
2025년 07월 23일

핵심 요약

  • 1 본 문서는 Ruby on Rails와 달리 Rack 기반 애플리케이션에서 코드 리로딩 기능을 구현하는 방법을 상세히 설명합니다.
  • 2 Zeitwerk, listen, concurrent-ruby 젬을 활용하여 개발 환경에서 코드 변경 시 서버 재시작 없이 즉시 반영되도록 하는 기법을 제시합니다.
  • 3 스레드 안전성 확보와 오래된 코드 참조 문제를 해결하는 구체적인 미들웨어 및 로더 구현 방안을 다룹니다.

도입

Ruby on Rails는 개발 생산성을 높이는 다양한 기능을 기본으로 제공하지만, 순수 Rack 기반 애플리케이션은 이러한 편의 기능, 특히 코드 리로딩을 직접 구현해야 합니다. 코드 리로딩은 개발 중 소스 코드 변경 시 웹 서버를 재시작하지 않고도 변경 사항을 즉시 반영하여 개발 워크플로우를 크게 개선합니다. 본 문서는 Zeitwerk, listen, concurrent-ruby 젬을 활용하여 Rack 애플리케이션에서 Rails와 유사한 수준의 효율적이고 스레드 안전한 코드 리로딩 메커니즘을 구축하는 방법을 심층적으로 탐구합니다. 특히 Puma와 같이 다중 스레드 및 프로세스를 사용하는 웹 서버 환경에서 발생할 수 있는 스레드 안전성 문제를 해결하는 데 중점을 둡니다.

먼저, 기본적인 Rack 애플리케이션 구조를 설정합니다. 여기에는 concurrent-ruby, listen, puma, rack, zeitwerk 젬을 포함하는 Gemfile과 config/environment.rb, lib/my_app.rb, config.ru 파일이 포함됩니다. 애플리케이션의 실제 코드는 src 폴더에 위치하도록 구성합니다. 이어서, 여러 스레드에서 호출되더라도 특정 블록이 단 한 번만 실행되도록 보장하는 Once 유틸리티 클래스를 소개합니다. 이는 코드 리로딩 프로세스 중 특정 초기화 작업이 중복 실행되는 것을 방지하는 데 활용됩니다.

핵심 구성 요소는 CodeLoader 클래스입니다. 이 클래스는 Zeitwerk 로더를 초기화하고, 주어진 경로의 코드를 로드하며, 개발 환경에서 리로딩이 활성화된 경우 파일 시스템 변경을 listen 젬을 통해 감지합니다. 특히 중요한 점은 Concurrent::ReadWriteLock을 사용하여 코드 리로딩 프로세스의 스레드 안전성을 보장한다는 것입니다. reload! 메서드가 호출되면, 변경 사항이 감지된 경우 쓰기 락을 획득하고 Zeitwerk의 reload 기능을 호출하여 코드를 다시 로드합니다. 프로덕션 환경에서는 리로딩을 비활성화하고 eager_load를 통해 애플리케이션 시작 시 모든 코드를 미리 로드하여 copy-on-write 성능 이점을 활용합니다.

다음으로 CodeLoaderMiddleware를 구현하여 CodeLoader를 Rack 애플리케이션의 요청 처리 파이프라인에 통합합니다. 이 미들웨어는 각 웹 요청이 들어올 때마다 CodeLoader#reload!를 호출하여 최신 코드 변경 사항을 확인하고 반영합니다. 또한, 코드 리로딩이 진행 중일 때는 읽기 락을 획득하여 다른 요청들이 안전하게 대기하도록 함으로써, 리로딩 중인 코드와 요청 처리 간의 충돌을 방지합니다.

마지막으로, 코드 리로딩 시 발생할 수 있는 ‘오래된 코드 참조(stale constant reference)’ 문제를 해결하는 방법을 제시합니다. Rack::Builder 내에서 run Foo와 같이 상수를 직접 참조하는 대신, run -> (env) { Foo.call(env) }와 같이 Proc으로 래핑하여 매 요청마다 Foo 상수가 최신 버전으로 해석되도록 합니다. 이는 CodeLoader#reloading_enabled? 메서드를 통해 개발 환경에서만 적용되어 불필요한 오버헤드를 줄입니다. 이러한 메커니즘을 통해 개발자는 서버를 재시작할 필요 없이 코드 변경 사항을 즉시 확인할 수 있게 됩니다.

결론

본 문서에서 제시된 `CodeLoader`와 `CodeLoaderMiddleware`는 Rack 애플리케이션에서 견고하고 효율적인 코드 리로딩 시스템을 구축하는 데 필수적인 구성 요소입니다. 이 접근 방식은 Ruby on Rails가 내부적으로 사용하는 코드 리로딩 메커니즘과 유사하며, 순수 Rack 환경에서도 Rails에 버금가는 개발 생산성을 제공합니다. 스레드 안전성을 고려한 설계와 오래된 코드 참조 문제 해결은 복잡한 웹 애플리케이션 환경에서도 안정적인 코드 리로딩을 가능하게 합니다. 결과적으로 개발자는 코드 변경 후 즉시 결과를 확인하며 신속하게 개발을 진행할 수 있어, 전반적인 개발 워크플로우의 효율성을 크게 향상시킬 수 있습니다.

댓글 0

댓글 작성

0/1000
정중하고 건설적인 댓글을 작성해 주세요.

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!