From 59c239d85cf8520c5da6e8cd07c8500823881251 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Thu, 29 Apr 2021 15:40:55 +0100 Subject: [PATCH] DEV: Speed up requests in development mode (#12890) On every request, Rails checks to see whether any ruby code has been changed on the filesystem. The default FileUpdateChecker does this by iterating over every file on the autoload_paths and comparing its modified-time. In Discourse, our autoload path of `/app` includes the `/app/assets` directory, and therefore thousands of non-ruby files (e.g. node_modules). This makes the `Dir["/app"]` call very slow (>100ms in my case). On my machine, every Rails-handled request spends around 150-200ms in the FileUpdateChecker. This commit introduces a couple of changes to completely eliminate this wasted time: - The `/app/assets` directory is excluded from the file watchers. For me, this cut the time spent in the file_watcher to around 50-100ms - Switches our development config to use the `EventedFileUpdateChecker`, which makes use of the `listen` gem to subscribe to os-specific notifications of changes. This completely removes the `FileUpdateChecker` from the critical path On my machine, topic_list requests now return in around 80ms (previously >200ms). Live code reload still works as it did before --- config/application.rb | 13 +++++++++++++ config/environments/development.rb | 1 + 2 files changed, 14 insertions(+) diff --git a/config/application.rb b/config/application.rb index b8294b14c18..f29044b5f63 100644 --- a/config/application.rb +++ b/config/application.rb @@ -120,6 +120,19 @@ module Discourse Rails.autoloaders.main.ignore(Dir["#{config.root}/app/models/reports"]) Rails.autoloaders.main.ignore(Dir["#{config.root}/lib/freedom_patches"]) + def watchable_args + files, dirs = super + + # Skip the assets directory. It doesn't contain any .rb files, so watching it + # is just slowing things down and raising warnings about node_modules symlinks + app_file_extensions = dirs.delete("#{config.root}/app") + Dir["#{config.root}/app/*"].reject { |path| path.end_with? "/assets" }.each do |path| + dirs[path] = app_file_extensions + end + + [files, dirs] + end + # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named. # config.plugins = [ :exception_notification, :ssl_requirement, :all ] diff --git a/config/environments/development.rb b/config/environments/development.rb index 53025e00656..8d9ffb6513c 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -7,6 +7,7 @@ Discourse::Application.configure do # every request. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. config.cache_classes = false + config.file_watcher = ActiveSupport::EventedFileUpdateChecker # Log error messages when you accidentally call methods on nil. config.eager_load = false