Rails App 시작 시 특정 코드 실행하기(How to startup code on Ruby on Rails with initialize)

Rails 앱 구동 시 특정 작업이나 로직을 수행하고 싶을 때 어떻게 할까? 고민을 예전에 했었는데, 그때 initialize로 해결했던 기억이 있습니다. 간만에 동일한 고민을 잠깐하게 됬었는데, 겸사겸사 글로 정리해둡니다.

요약하자면 application.rb 에서 config.after_initialize로 Rails 실행 시 동작할 로직을 넣어줄 수 있습니다.

config/application.rb

config.after_initialize do
    # ....
end

그래서 코드를 작성하면 약간 이런 느낌이겠네요.

module YourApp
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.2

    # 앱 시작 시 실행되는 부분
    config.after_initialize do
      system('curl -i -k localhost:3000/zfdf')
      p 'init!!!'
    end

    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.

    # Don't generate system test files.
    config.generators.system_tests = nil
  end
end

=>

다만 이대로 돌리게되면 rails 앱이 올라오기 전에 curl 요청이 발생합니다. 이유는 Rails 구동 프로세스 떄문에 그렇습니다. 코드 내 initialize는 Rails 전체에 대한 init이 아니라 environment initializer 같이 구동 앞단에만 동작하는 부분이라 after_initialize 라고 하여도 실제로 앱 구동 이후 시점이 아닙니다.

구조라고 표현하기도 애매하지만, 아무튼 서버 실행보다 앞단입니다.

그래서 약간 꼼수를 쓰면…

config.after_initialize do
  Thread.new do
    Rails.application.executor.wrap do
      system('sleep 5 ; curl -i -k localhost:3000/zfdf')
    end
  end
  #system('bundle exec crono')
  p 'init!!!'
end

이런식으로 쓰레드 처리하고 좀 기다렸다가 curl 날리면 정상 요청 가능합니다. 이걸로 crono 스케줄링을 돌리면 Rails 앱 시작 시 자동으로 시작될거라 생각했으나, 문제가 있었습니다. 바로 프로세스가 엄청 여러개가 실행되는거였는데 찾아보니 비슷한 사례가 있었네요.

Never start your process in Rails initialization files. It might start the process several times when there are few application workers on your server. Or it might start the process when you start the Rails console and so on.

https://stackoverflow.com/questions/38703514/ruby-on-rails-how-to-run-a-background-task-automatically-when-the-server-starts

이거에 대한 해결방법은 장기적인(?) 과제로 남겨두고 우선 개인프로젝트 진행하던건 마무리할까 합니다. (이렇게라도 메모 안해두면 나중에 또 삽질하고 있겠죠…)

f*…

6 Initialization events

  • before_configuration : Rails :: Application에서 상속 받자 마자 실행됩니다.
  • before_initialize : 초기화 프로세스가 : bootstrap_hook을 사용하여 Rails 초기화 구간이 시작되기 직전에 바로 실행됩니다.
  • to_prepare : 모든 초기화 프로세스가 동작할때 마다 실행됩니다.
  • before_eager_load : eager loading이 발생하기 직전에 실행됩니다.
  • after_initialize : config / initializers 의 초기화 후 바로 실행됩니다.

Reference

https://guides.rubyonrails.org/configuring.html https://stackoverflow.com/questions/8543904/how-to-run-my-ruby-code-after-rails-server-start