From 80a9b5d5b567d9937512d0bb0a1b78e0b37585e2 Mon Sep 17 00:00:00 2001 From: potashin Date: Wed, 22 May 2024 23:33:58 +0300 Subject: [PATCH 1/7] config: backend setup --- .ruby-version | 2 +- Gemfile | 2 +- Gemfile.lock | 6 +++--- bin/webpack-dev-server | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.ruby-version b/.ruby-version index ec1cf33c..6a81b4c8 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.6.3 +2.7.8 diff --git a/Gemfile b/Gemfile index 1a5f4c0b..eb4f3a68 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ # rubocop:disable LineLength source "https://rubygems.org" -ruby "2.6.3" +ruby "2.7.8" # Enforce git to transmitted via https. # workaround until bundler 2.0 is released. diff --git a/Gemfile.lock b/Gemfile.lock index c7c050cf..4d934c9a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -175,7 +175,7 @@ GEM bundler-audit (0.6.0) bundler (~> 1.2) thor (~> 0.18) - byebug (11.0.0) + byebug (11.1.3) capybara (3.13.2) addressable mini_mime (>= 0.1.3) @@ -654,7 +654,7 @@ GEM pry (0.12.2) coderay (~> 1.1.0) method_source (~> 0.9.0) - pry-byebug (3.7.0) + pry-byebug (3.8.0) byebug (~> 11.0) pry (~> 0.10) pry-rails (0.3.9) @@ -1082,7 +1082,7 @@ DEPENDENCIES zonebie (~> 0.6.1) RUBY VERSION - ruby 2.6.3p62 + ruby 2.7.8p225 BUNDLED WITH 1.17.3 diff --git a/bin/webpack-dev-server b/bin/webpack-dev-server index 63edc01e..67347f3c 100755 --- a/bin/webpack-dev-server +++ b/bin/webpack-dev-server @@ -24,7 +24,7 @@ def args(key) end begin - dev_server = YAML.load_file(CONFIG_FILE)[RAILS_ENV]["dev_server"] + dev_server = YAML.load_file(CONFIG_FILE, aliases: true)[RAILS_ENV]["dev_server"] HOSTNAME = args("--host") || dev_server["host"] PORT = args("--port") || dev_server["port"] From e9a5d2808c52a9f5f56d67241c21c7ba2bae2546 Mon Sep 17 00:00:00 2001 From: potashin Date: Thu, 23 May 2024 12:55:15 +0300 Subject: [PATCH 2/7] config: setup new relic --- Gemfile | 1 + Gemfile.lock | 2 ++ config/newrelic.yml | 66 +++++++++++++++++++++++++++++++++++ config/sample_application.yml | 3 ++ 4 files changed, 72 insertions(+) create mode 100644 config/newrelic.yml diff --git a/Gemfile b/Gemfile index eb4f3a68..e509ccea 100644 --- a/Gemfile +++ b/Gemfile @@ -102,6 +102,7 @@ gem "uglifier", "~> 4.1" gem "validate_url", "~> 1.0" gem "webpacker", "~> 3.5" gem "webpush", "~> 0.3" +gem 'newrelic_rpm' group :development do gem "better_errors", "~> 2.5" diff --git a/Gemfile.lock b/Gemfile.lock index 4d934c9a..0ac0b051 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -612,6 +612,7 @@ GEM net-http-persistent (3.0.0) connection_pool (~> 2.2) netrc (0.11.0) + newrelic_rpm (9.9.0) nio4r (2.3.1) nokogiri (1.10.1) mini_portile2 (~> 2.4.0) @@ -1013,6 +1014,7 @@ DEPENDENCIES liquid (~> 4.0) memory_profiler (~> 0.9) nakayoshi_fork + newrelic_rpm nokogiri (~> 1.10) octokit (~> 4.13) omniauth (~> 1.9) diff --git a/config/newrelic.yml b/config/newrelic.yml new file mode 100644 index 00000000..c57dab44 --- /dev/null +++ b/config/newrelic.yml @@ -0,0 +1,66 @@ +# +# This file configures the New Relic Agent. New Relic monitors Ruby, Java, +# .NET, PHP, Python, Node, and Go applications with deep visibility and low +# overhead. For more information, visit www.newrelic.com. +# +# Generated October 28, 2022 +# +# This configuration file is custom generated for NewRelic Administration +# +# For full documentation of agent configuration options, please refer to +# https://docs.newrelic.com/docs/agents/ruby-agent/installation-configuration/ruby-agent-configuration + +common: &default_settings + # Required license key associated with your New Relic account. + license_key: <%= ENV['NEW_RELIC_LICENCE_KEY'] %> + + # Your application name. Renaming here affects where data displays in New + # Relic. For more details, see https://docs.newrelic.com/docs/apm/new-relic-apm/maintenance/renaming-applications + app_name: 'dev_to_copy' + + distributed_tracing: + enabled: true + + # To disable the agent regardless of other settings, uncomment the following: + + # agent_enabled: false + + # Logging level for log/newrelic_agent.log + log_level: info + + application_logging: + # If `true`, all logging-related features for the agent can be enabled or disabled + # independently. If `false`, all logging-related features are disabled. + enabled: true + forwarding: + # If `true`, the agent captures log records emitted by this application. + enabled: true + # Defines the maximum number of log records to buffer in memory at a time. + max_samples_stored: 10000 + metrics: + # If `true`, the agent captures metrics related to logging for this application. + enabled: true + local_decorating: + # If `true`, the agent decorates logs with metadata to link to entities, hosts, traces, and spans. + # This requires a log forwarder to send your log files to New Relic. + # This should not be used when forwarding is enabled. + enabled: false + +# Environment-specific settings are in this section. +# RAILS_ENV or RACK_ENV (as appropriate) is used to determine the environment. +# If your application has other named environments, configure them here. +development: + <<: *default_settings + app_name: 'dev_to_copy (Development)' + +test: + <<: *default_settings + # It doesn't make sense to report to New Relic from automated test runs. + monitor_mode: false + +staging: + <<: *default_settings + app_name: 'dev_to_copy (Staging)' + +production: + <<: *default_settings diff --git a/config/sample_application.yml b/config/sample_application.yml index a829dae5..57bbbdcb 100644 --- a/config/sample_application.yml +++ b/config/sample_application.yml @@ -15,3 +15,6 @@ PUSHER_APP_ID: PUSHER_KEY: PUSHER_SECRET: PUSHER_CLUSTER: + + +NEW_RELIC_LICENCE_KEY: From 5adb3ca785d0033648a598201707dc5d4b7142f8 Mon Sep 17 00:00:00 2001 From: potashin Date: Sat, 25 May 2024 14:35:47 +0300 Subject: [PATCH 3/7] config: setup rails-panel --- Gemfile | 1 + Gemfile.lock | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/Gemfile b/Gemfile index e509ccea..2977affa 100644 --- a/Gemfile +++ b/Gemfile @@ -116,6 +116,7 @@ group :development do gem "guard-rspec", "~> 4.7", require: false gem "rb-fsevent", "~> 0.10", require: false gem "web-console", "~> 3.7" + gem 'meta_request' end group :development, :test do diff --git a/Gemfile.lock b/Gemfile.lock index 0ac0b051..5a297d39 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -592,6 +592,9 @@ GEM memoizable (0.4.2) thread_safe (~> 0.3, >= 0.3.1) memory_profiler (0.9.12) + meta_request (0.8.2) + rack-contrib (>= 1.1, < 3) + railties (>= 3.0.0, < 8) method_source (0.9.2) mime-types (3.2.2) mime-types-data (~> 3.2015) @@ -676,6 +679,8 @@ GEM pusher-signature (0.1.8) raabro (1.1.6) rack (2.0.6) + rack-contrib (2.5.0) + rack (< 4) rack-host-redirect (1.3.0) rack rack-protection (2.0.4) @@ -1013,6 +1018,7 @@ DEPENDENCIES libhoney (~> 1.11) liquid (~> 4.0) memory_profiler (~> 0.9) + meta_request nakayoshi_fork newrelic_rpm nokogiri (~> 1.10) From 700faf39e8c5d654811c3f06d561be10f03c1a86 Mon Sep 17 00:00:00 2001 From: potashin Date: Sat, 25 May 2024 16:14:35 +0300 Subject: [PATCH 4/7] config: setup rack mini profiler --- Gemfile | 3 +- Gemfile.lock | 49 +++++++++++++---------- app/controllers/application_controller.rb | 16 ++++++++ config/environments/production.rb | 4 ++ config/initializers/rack_mini_profiler.rb | 9 +++++ config/sample_application.yml | 2 + 6 files changed, 61 insertions(+), 22 deletions(-) create mode 100644 config/initializers/rack_mini_profiler.rb diff --git a/Gemfile b/Gemfile index 2977affa..e1103057 100644 --- a/Gemfile +++ b/Gemfile @@ -103,6 +103,7 @@ gem "validate_url", "~> 1.0" gem "webpacker", "~> 3.5" gem "webpush", "~> 0.3" gem 'newrelic_rpm' +gem 'rack-mini-profiler', require: false group :development do gem "better_errors", "~> 2.5" @@ -116,7 +117,7 @@ group :development do gem "guard-rspec", "~> 4.7", require: false gem "rb-fsevent", "~> 0.10", require: false gem "web-console", "~> 3.7" - gem 'meta_request' + # gem 'meta_request' end group :development, :test do diff --git a/Gemfile.lock b/Gemfile.lock index 5a297d39..a4f57100 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -151,7 +151,7 @@ GEM html_tokenizer (~> 0.0.6) parser (>= 2.4) smart_properties - bindex (0.5.0) + bindex (0.8.1) binding_of_caller (0.8.0) debug_inspector (>= 0.0.1) bourbon (5.1.0) @@ -168,7 +168,7 @@ GEM rake yajl-ruby buftok (0.2.0) - builder (3.2.3) + builder (3.2.4) bullet (5.9.0) activesupport (>= 3.0.0) uniform_notifier (~> 1.11) @@ -212,7 +212,7 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.1.5) + concurrent-ruby (1.2.3) connection_pool (2.2.2) counter_culture (2.1.2) activerecord (>= 3.0.0) @@ -220,7 +220,7 @@ GEM after_commit_action (~> 1.0) crack (0.4.3) safe_yaml (~> 1.0.0) - crass (1.0.4) + crass (1.0.6) csv_shaper (1.3.0) activesupport (>= 3.0.0) dalli (2.7.9) @@ -288,7 +288,7 @@ GEM rubocop (~> 0.51) smart_properties errbase (0.1.0) - erubi (1.8.0) + erubi (1.12.0) et-orbi (1.1.6) tzinfo eventmachine (1.2.5) @@ -536,7 +536,7 @@ GEM mime-types (~> 3.0) multi_xml (>= 0.5.2) httpclient (2.8.3) - i18n (1.6.0) + i18n (1.14.5) concurrent-ruby (~> 1.0) ice_nine (0.11.2) inflecto (0.0.2) @@ -582,9 +582,9 @@ GEM rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) ruby_dep (~> 1.2) - loofah (2.2.3) + loofah (2.22.0) crass (~> 1.0.2) - nokogiri (>= 1.5.9) + nokogiri (>= 1.12.0) lumberjack (1.0.13) mail (2.7.1) mini_mime (>= 0.1.1) @@ -600,8 +600,8 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2018.0812) mini_mime (1.0.1) - mini_portile2 (2.4.0) - minitest (5.11.3) + mini_portile2 (2.8.6) + minitest (5.23.1) momentjs-rails (2.20.1) railties (>= 3.1) msgpack (1.2.4) @@ -617,8 +617,9 @@ GEM netrc (0.11.0) newrelic_rpm (9.9.0) nio4r (2.3.1) - nokogiri (1.10.1) - mini_portile2 (~> 2.4.0) + nokogiri (1.15.6) + mini_portile2 (~> 2.8.2) + racc (~> 1.4) notiffany (0.1.1) nenv (~> 0.1) shellany (~> 0.0) @@ -678,17 +679,20 @@ GEM rest-client pusher-signature (0.1.8) raabro (1.1.6) - rack (2.0.6) + racc (1.8.0) + rack (2.2.9) rack-contrib (2.5.0) rack (< 4) rack-host-redirect (1.3.0) rack + rack-mini-profiler (3.3.1) + rack (>= 1.2.0) rack-protection (2.0.4) rack rack-proxy (0.6.5) rack - rack-test (1.1.0) - rack (>= 1.0, < 3) + rack-test (2.1.0) + rack (>= 1.3) rack-timeout (0.5.1) rails (5.1.6.2) actioncable (= 5.1.6.2) @@ -707,11 +711,13 @@ GEM actionpack (>= 5.0.1.x) actionview (>= 5.0.1.x) activesupport (>= 5.0.1.x) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.0.4) - loofah (~> 2.2, >= 2.2.2) + rails-html-sanitizer (1.6.0) + loofah (~> 2.21) + nokogiri (~> 1.14) rails-observers (0.1.5) activemodel (>= 4.0) railties (5.1.6.2) @@ -721,7 +727,7 @@ GEM rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rainbow (3.0.0) - rake (12.3.2) + rake (12.3.3) rb-fsevent (0.10.3) rb-inotify (0.9.10) ffi (>= 0.5.0, < 2) @@ -901,7 +907,7 @@ GEM multipart-post (~> 2.0) naught (~> 1.0) simple_oauth (~> 0.3.0) - tzinfo (1.2.5) + tzinfo (1.2.11) thread_safe (~> 0.1) uber (0.1.0) uglifier (4.1.20) @@ -1037,6 +1043,7 @@ DEPENDENCIES pusher (~> 1.3) pusher-push-notifications (~> 1.0) rack-host-redirect (~> 1.3) + rack-mini-profiler rack-timeout (~> 0.5) rails (~> 5.1.6) rails-assets-airbrake-js-client (~> 1.5)! diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1531dc97..0da3d0cb 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -4,6 +4,8 @@ class ApplicationController < ActionController::Base include Pundit include Instrumentation + before_action :authorize_rmp, if: :authorize_rmp? + def require_http_auth authenticate_or_request_with_http_basic do |username, password| username == ApplicationConfig["APP_NAME"] && password == ApplicationConfig["APP_PASSWORD"] @@ -78,4 +80,18 @@ def append_info_to_payload(payload) super(payload) append_to_honeycomb(request, self.class.name) end + + def authorize_rmp + Rack::MiniProfiler.authorize_request + end + + def authorize_rmp? + return true unless Rails.env.production? + + if current_user + current_user.admin? + else + ENV['RMP_TOKEN'] == params[:rmp_token] + end + end end diff --git a/config/environments/production.rb b/config/environments/production.rb index 9926e830..709bfff5 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -126,6 +126,10 @@ config.middleware.use Rack::HostRedirect, "practicaldev.herokuapp.com" => "dev.to" + + + Rack::MiniProfiler.config.storage_options = { url: (ENV["MEMCACHIER_SERVERS"] || "").split(",")[0] } + Rack::MiniProfiler.config.storage = Rack::MiniProfiler::MemcacheStore end # rubocop:enable Metrics/BlockLength diff --git a/config/initializers/rack_mini_profiler.rb b/config/initializers/rack_mini_profiler.rb new file mode 100644 index 00000000..7940815a --- /dev/null +++ b/config/initializers/rack_mini_profiler.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require "rack-mini-profiler" + +# The initializer was required late, so initialize it manually. +Rack::MiniProfilerRails.initialize!(Rails.application) + +Rails.application.middleware.delete(Rack::MiniProfiler) +Rails.application.middleware.insert_after(Rack::Deflater, Rack::MiniProfiler) diff --git a/config/sample_application.yml b/config/sample_application.yml index 57bbbdcb..a5f18ef2 100644 --- a/config/sample_application.yml +++ b/config/sample_application.yml @@ -18,3 +18,5 @@ PUSHER_CLUSTER: NEW_RELIC_LICENCE_KEY: + +SKYLIGHT_AUTHENTICATION: From d67a50f087de365a2abe791d47222959a35a1ae6 Mon Sep 17 00:00:00 2001 From: potashin Date: Sat, 25 May 2024 21:59:35 +0300 Subject: [PATCH 5/7] config: setup grafana-prometheus --- Gemfile | 4 +++ Gemfile.lock | 36 +++++++++++++++---- config.ru | 1 + config/initializers/influxdb_rails.rb | 45 ++++++++++++++++++++++++ config/initializers/yabeda_prometheus.rb | 5 +++ config/puma.rb | 3 ++ config/sample_application.yml | 5 +++ 7 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 config/initializers/influxdb_rails.rb create mode 100644 config/initializers/yabeda_prometheus.rb diff --git a/Gemfile b/Gemfile index e1103057..7867b9a8 100644 --- a/Gemfile +++ b/Gemfile @@ -104,6 +104,10 @@ gem "webpacker", "~> 3.5" gem "webpush", "~> 0.3" gem 'newrelic_rpm' gem 'rack-mini-profiler', require: false +gem 'yabeda-prometheus' +gem 'yabeda-rails' +gem 'yabeda-puma-plugin' +gem 'influxdb-rails' group :development do gem "better_errors", "~> 2.5" diff --git a/Gemfile.lock b/Gemfile.lock index a4f57100..69ee8d57 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -112,6 +112,8 @@ GEM json (~> 1.8) ancestry (3.0.5) activerecord (>= 3.2.0) + anyway_config (2.6.4) + ruby-next-core (~> 1.0) approvals (0.0.24) nokogiri (~> 1.6) thor (~> 0.18) @@ -269,6 +271,7 @@ GEM activemodel-serializers-xml (~> 1.0) activesupport (~> 5.0) request_store (~> 1.0) + dry-initializer (3.1.1) em-websocket (0.5.1) eventmachine (>= 0.12.9) http_parser.rb (~> 0.6.0) @@ -540,6 +543,10 @@ GEM concurrent-ruby (~> 1.0) ice_nine (0.11.2) inflecto (0.0.2) + influxdb (0.8.1) + influxdb-rails (1.0.3) + influxdb (~> 0.6, >= 0.6.4) + railties (>= 5.0) inline_svg (1.3.1) activesupport (>= 3.0) nokogiri (>= 1.6) @@ -592,9 +599,6 @@ GEM memoizable (0.4.2) thread_safe (~> 0.3, >= 0.3.1) memory_profiler (0.9.12) - meta_request (0.8.2) - rack-contrib (>= 1.1, < 3) - railties (>= 3.0.0, < 8) method_source (0.9.2) mime-types (3.2.2) mime-types-data (~> 3.2015) @@ -656,6 +660,7 @@ GEM ast (~> 2.4.0) pg (1.1.4) powerpack (0.1.2) + prometheus-client (4.2.2) pry (0.12.2) coderay (~> 1.1.0) method_source (~> 0.9.0) @@ -681,8 +686,6 @@ GEM raabro (1.1.6) racc (1.8.0) rack (2.2.9) - rack-contrib (2.5.0) - rack (< 4) rack-host-redirect (1.3.0) rack rack-mini-profiler (3.3.1) @@ -793,6 +796,7 @@ GEM unicode-display_width (~> 1.4.0) rubocop-rspec (1.31.0) rubocop (>= 0.60.0) + ruby-next-core (1.0.3) ruby-prof (0.17.0) ruby-progressbar (1.10.0) ruby_dep (1.5.0) @@ -950,6 +954,23 @@ GEM xml-simple (1.1.5) xpath (3.2.0) nokogiri (~> 1.8) + yabeda (0.12.0) + anyway_config (>= 1.0, < 3) + concurrent-ruby + dry-initializer + yabeda-prometheus (0.9.1) + prometheus-client (>= 3.0, < 5.0) + rack + yabeda (~> 0.10) + yabeda-puma-plugin (0.7.1) + json + puma + yabeda (~> 0.5) + yabeda-rails (0.9.0) + activesupport + anyway_config (>= 1.3, < 3) + railties + yabeda (~> 0.8) yajl-ruby (1.4.1) zonebie (0.6.1) @@ -1016,6 +1037,7 @@ DEPENDENCIES honeycomb-rails html_truncator (~> 0.4) httparty (~> 0.16) + influxdb-rails inline_svg (~> 1.3) jbuilder (~> 2.8) jquery-rails (~> 4.3) @@ -1024,7 +1046,6 @@ DEPENDENCIES libhoney (~> 1.11) liquid (~> 4.0) memory_profiler (~> 0.9) - meta_request nakayoshi_fork newrelic_rpm nokogiri (~> 1.10) @@ -1094,6 +1115,9 @@ DEPENDENCIES webmock (~> 3.5) webpacker (~> 3.5) webpush (~> 0.3) + yabeda-prometheus + yabeda-puma-plugin + yabeda-rails zonebie (~> 0.6.1) RUBY VERSION diff --git a/config.ru b/config.ru index 193e5fed..37152a30 100644 --- a/config.ru +++ b/config.ru @@ -1,4 +1,5 @@ # This file is used by Rack-based servers to start the application. require ::File.expand_path("../config/environment", __FILE__) +use Yabeda::Prometheus::Exporter run Rails.application diff --git a/config/initializers/influxdb_rails.rb b/config/initializers/influxdb_rails.rb new file mode 100644 index 00000000..bdf32d9e --- /dev/null +++ b/config/initializers/influxdb_rails.rb @@ -0,0 +1,45 @@ +InfluxDB::Rails.configure do |config| + ## The only setting you actually need to update is the name of the + ## database within the InfluxDB server instance. Don't forget to + ## create this database as well. + config.client.database = ENV['INFLUX_DB_NAME'] + # config.client.hosts = ["localhost"] + # config.client.port = 8086 + + ## If you've setup user authentication (and activated it in the server + ## config), you need to configure the credentials here. + config.client.username = ENV['INFLUX_DB_USER'] + config.client.password = ENV['INFLUX_DB_PASSWORD'] + + ## If your InfluxDB service requires an HTTPS connection then you can + ## enable it here. + # config.client.use_ssl = true + + ## Various other client and connection options. These are used to create + ## an `InfluxDB::Client` instance (i.e. `InfluxDB::Rails.client`). + ## + ## See docs for the influxdb gem for the canonical list of options: + ## https://github.com/influxdata/influxdb-ruby#list-of-configuration-options + ## + ## These defaults for the influxdb-rails gem deviate from the default + ## for the influxdb gem: + # config.client.async = true # false + # config.client.read_timeout = 30 # 300 + # config.client.max_delay = 300 # 30 + # config.client.time_precision = "ms" # "s" + + ## Prior to 1.0.0, this gem has written all data points in different + ## measurements (the config options were named `series_name_for_*`). + ## Since 1.0.0.beta3, we're now using a single measurements + # config.measurement_name = "rails" + + ## Disable rails framework hooks. + # config.ignored_hooks = ['sql.active_record', 'render_template.action_view'] + + # Modify tags on the fly. + # config.tags_middleware = ->(tags) { tags } + + ## Set the application name to something meaningful, by default we + ## infer the app name from the Rails.application class name. + # config.application_name = Rails.application.class.parent_name +end diff --git a/config/initializers/yabeda_prometheus.rb b/config/initializers/yabeda_prometheus.rb new file mode 100644 index 00000000..c17b699c --- /dev/null +++ b/config/initializers/yabeda_prometheus.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +unless %w[development test].include?(Rails.env) + Yabeda::Prometheus::Exporter.start_metrics_server! +end diff --git a/config/puma.rb b/config/puma.rb index 3d5df906..372c4d72 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -16,3 +16,6 @@ # See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot ActiveRecord::Base.establish_connection end + +activate_control_app +plugin :yabeda diff --git a/config/sample_application.yml b/config/sample_application.yml index a5f18ef2..fa56c485 100644 --- a/config/sample_application.yml +++ b/config/sample_application.yml @@ -20,3 +20,8 @@ PUSHER_CLUSTER: NEW_RELIC_LICENCE_KEY: SKYLIGHT_AUTHENTICATION: + +INFLUX_DB_NAME: +INFLUX_DB_USER: +INFLUX_DB_PASSWORD: + From 595f540a237d39ca3ec4d5607dd0b469e472e08e Mon Sep 17 00:00:00 2001 From: potashin Date: Sun, 26 May 2024 20:45:03 +0300 Subject: [PATCH 6/7] config: setup local production --- config/environments/local_production.rb | 110 ++++++++++++++++++++++ config/initializers/honeycomb.rb | 2 +- config/initializers/rack_mini_profiler.rb | 7 +- config/newrelic.yml | 4 + config/secrets.yml | 2 + config/webpack/local_production.js | 7 ++ config/webpacker.yml | 10 ++ 7 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 config/environments/local_production.rb create mode 100644 config/webpack/local_production.js diff --git a/config/environments/local_production.rb b/config/environments/local_production.rb new file mode 100644 index 00000000..14a07806 --- /dev/null +++ b/config/environments/local_production.rb @@ -0,0 +1,110 @@ +# rubocop:disable Metrics/BlockLength +# +def yarn_integrity_enabled? + ENV.fetch("YARN_INTEGRITY_ENABLED", "true") == "true" +end + +Rails.application.configure do + + + # Verifies that versions and hashed value of the package contents in the project's package.json + config.webpacker.check_yarn_integrity = yarn_integrity_enabled? + + # Settings specified here will take precedence over those in config/application.rb. + + # In the development environment your application's code is reloaded on + # 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 = true + + # Do not eager load code on boot. + config.eager_load = true + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + + # Enable/disable caching. By default caching is disabled. + # if Rails.root.join("tmp/caching-dev.txt").exist? + config.action_controller.perform_caching = true + + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=172800" + } + # else + # config.action_controller.perform_caching = false + + # config.cache_store = :null_store + # end + + # Don't care if the mailer can't send. + config.action_mailer.raise_delivery_errors = false + + # Print deprecation notices to the Rails logger. + config.active_support.deprecation = :log + + # Raise an error on page load if there are pending migrations. + config.active_record.migration_error = false + + # Debug mode disables concatenation and preprocessing of assets. + # This option may cause significant delays in view rendering with a large + # number of complex assets. + config.assets.debug = false + + # Asset digests allow you to set far-future HTTP expiration dates on all assets, + # yet still be able to expire them through the digest params. + config.assets.digest = false + + # Supress logger output for asset requests. + config.assets.quiet = true + + # Compress JavaScripts and CSS. + config.assets.js_compressor = Uglifier.new(harmony: true) + # config.assets.css_compressor = :sass + + # Do not fallback to assets pipeline if a precompiled asset is missed. + config.assets.compile = true + + # Adds additional error checking when serving assets at runtime. + # Checks for improperly declared sprockets dependencies. + # Raises helpful error messages. + config.assets.raise_runtime_errors = true + + config.action_mailer.perform_caching = false + + config.serve_static_files = true + + config.app_domain = "localhost:3000" + + config.action_mailer.default_url_options = { host: "localhost:3000" } + config.action_mailer.delivery_method = :smtp + config.action_mailer.perform_deliveries = true + config.action_mailer.default_url_options = { host: config.app_domain } + config.action_mailer.smtp_settings = { + address: "smtp.gmail.com", + port: "587", + enable_starttls_auto: true, + user_name: '<%= ENV["DEVELOPMENT_EMAIL_USERNAME"] %>', + password: '<%= ENV["DEVELOPMENT_EMAIL_PASSWORD"] %>', + authentication: :plain, + domain: "localhost:3000" + } + + config.action_mailer.preview_path = "#{Rails.root}/spec/mailers/previews" + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true + + config.public_file_server.enabled = true + + config.file_watcher = ActiveSupport::EventedFileUpdateChecker + + # Install the Timber.io logger + send_logs_to_timber = ENV["SEND_LOGS_TO_TIMBER"] || "false" # <---- set to false to stop sending dev logs to Timber.io + log_device = send_logs_to_timber == "true" ? Timber::LogDevices::HTTP.new(ENV["TIMBER"]) : STDOUT + logger = Timber::Logger.new(log_device) + logger.level = config.log_level + config.logger = ActiveSupport::TaggedLogging.new(logger) +end + +# rubocop:enable Metrics/BlockLength diff --git a/config/initializers/honeycomb.rb b/config/initializers/honeycomb.rb index 0ac4787a..dacd20c6 100644 --- a/config/initializers/honeycomb.rb +++ b/config/initializers/honeycomb.rb @@ -3,7 +3,7 @@ key = ApplicationConfig["HONEYCOMB_API_KEY"] dataset = "dev.to-#{Rails.env}" -$libhoney = if Rails.env.development? || Rails.env.test? +$libhoney = if Rails.env.development? || Rails.env.test? || Rails.env.local_production? Libhoney::NullClient.new else Libhoney::Client.new( diff --git a/config/initializers/rack_mini_profiler.rb b/config/initializers/rack_mini_profiler.rb index 7940815a..21ae0f7d 100644 --- a/config/initializers/rack_mini_profiler.rb +++ b/config/initializers/rack_mini_profiler.rb @@ -5,5 +5,8 @@ # The initializer was required late, so initialize it manually. Rack::MiniProfilerRails.initialize!(Rails.application) -Rails.application.middleware.delete(Rack::MiniProfiler) -Rails.application.middleware.insert_after(Rack::Deflater, Rack::MiniProfiler) +if Rails.env.production? || Rails.env.staging? + Rails.application.middleware.delete(Rack::MiniProfiler) + Rails.application.middleware.insert_after(Rack::Deflater, Rack::MiniProfiler) + Rack::MiniProfiler.config.authorization_mode = :allow_authorized +end diff --git a/config/newrelic.yml b/config/newrelic.yml index c57dab44..407935a8 100644 --- a/config/newrelic.yml +++ b/config/newrelic.yml @@ -53,6 +53,10 @@ development: <<: *default_settings app_name: 'dev_to_copy (Development)' +local_production: + <<: *default_settings + app_name: 'dev_to_copy (Local production)' + test: <<: *default_settings # It doesn't make sense to report to New Relic from automated test runs. diff --git a/config/secrets.yml b/config/secrets.yml index 73f5e05c..d9f6e5ee 100644 --- a/config/secrets.yml +++ b/config/secrets.yml @@ -16,6 +16,8 @@ development: test: secret_key_base: 42dd7834039ebbea271af22635a6782ee15e519b14629c5276bfcdd4cff841e9926994784bb43a335a8f8c9739bb254ea3afe831839d4dc65654ec7516ec25f0 +local_production: + secret_key_base: fd7bf490758ecf29d39560b38c622a0521e9b48bbee8c022ff749309826f0f3270ed0b04f05c3d51d9f821b26755f64ffb05dbe5c316e6d9060a95e443aca1ef # Do not keep production secrets in the repository, # instead read values from the environment. diff --git a/config/webpack/local_production.js b/config/webpack/local_production.js new file mode 100644 index 00000000..009652d5 --- /dev/null +++ b/config/webpack/local_production.js @@ -0,0 +1,7 @@ +const environment = require('./environment'); +const config = environment.toWebpackConfig(); + +// For more information, see https://webpack.js.org/configuration/devtool/#devtool +config.devtool = 'eval-source-map'; + +module.exports = config; diff --git a/config/webpacker.yml b/config/webpacker.yml index 2dfcd170..caab6b3f 100644 --- a/config/webpacker.yml +++ b/config/webpacker.yml @@ -46,6 +46,16 @@ test: # Compile test packs to a separate directory public_output_path: packs-test +local_production: + <<: *default + compile: true + + dev_server: + host: localhost + port: 3035 + hmr: false + https: false + production: <<: *default From 1a0d50781d4dc98c89564d7fe6d027398a129200 Mon Sep 17 00:00:00 2001 From: potashin Date: Sun, 26 May 2024 23:03:15 +0300 Subject: [PATCH 7/7] chore: optimization --- app/views/stories/_main_stories_feed.html.erb | 14 ++- case-study.md | 104 ++++++++++++++++++ config/environments/local_production.rb | 10 +- 3 files changed, 117 insertions(+), 11 deletions(-) create mode 100644 case-study.md diff --git a/app/views/stories/_main_stories_feed.html.erb b/app/views/stories/_main_stories_feed.html.erb index b6cd0a65..04e84d70 100644 --- a/app/views/stories/_main_stories_feed.html.erb +++ b/app/views/stories/_main_stories_feed.html.erb @@ -50,13 +50,15 @@ <% end %> <% else %> - <% @stories.each_with_index do |story, i| %> - <% next if story.id == @featured_story.id %> - <% if !user_signed_in? && i == 4 %> - <%= render "stories/sign_in_invitation" %> + <% @stories.each_with_index do |story, i| %> + <% next if story.id == @featured_story.id %> + <% if !user_signed_in? && i == 4 %> + <%= render "stories/sign_in_invitation" %> + <% end %> + <% cache(story) do %> + <%= render "articles/single_story", story: story %> + <% end %> <% end %> - <%= render "articles/single_story", story: story %> - <% end %> <% end %> <% if @stories.size > 1 %>
diff --git a/case-study.md b/case-study.md new file mode 100644 index 00000000..e9488b63 --- /dev/null +++ b/case-study.md @@ -0,0 +1,104 @@ +Case-study оптимизации + +## Актуальная проблема + +Нужно оптимизировать механизм загрузки главной страницы проекта `StoriesController#index`. + +Я решил исправить эту проблему, оптимизировав рендеринг шаблонов. + +## Формирование метрики + +Для того, чтобы понимать, дают ли мои изменения положительный эффект на быстродействие программы я придумал использовать такую метрику: число секунд, требуемые для прохождения нагрузочного бенчмарка `ab` с 100 запросами к главной странице проекта. Результаты: + +``` + Document Path: / + Document Length: 137188 bytes + + Concurrency Level: 1 + Time taken for tests: 5.048 seconds + Complete requests: 100 + Failed requests: 0 + Total transferred: 13773200 bytes + HTML transferred: 13718800 bytes + Requests per second: 19.81 [#/sec] (mean) + Time per request: 50.475 [ms] (mean) + Time per request: 50.475 [ms] (mean, across all concurrent requests) + Transfer rate: 2664.75 [Kbytes/sec] received + + Connection Times (ms) + min mean[+/-sd] median max + Connect: 0 0 0.1 0 0 + Processing: 39 50 18.3 45 165 + Waiting: 39 50 18.3 45 164 + Total: 39 50 18.3 45 165 + + Percentage of the requests served within a certain time (ms) + 50% 45 + 66% 48 + 75% 50 + 80% 51 + 90% 64 + 95% 84 + 98% 138 + 99% 165 + 100% 165 (longest request) +``` + +## Вникаем в детали системы, чтобы найти главные точки роста + +Для того, чтобы найти "точки роста" для оптимизации я воспользовался rack-mini-profiler. + +### Ваша находка №1 + +- rack-mini-profiler показал заметное время занимает рендеринг partial `articles/_single_story.html.erb` (24 вызова в контексте `Rendering: stories/_main_stories_feed.html.er... 4.6 +23.2`). + +- добавил кеширование фрагмента: + + ``` + <% cache(story) do %> + <%= render "articles/single_story", story: story %> + <% end %> + ``` + +- метрика снизилась с 5с до 3.5с + +``` +Document Path: / +Document Length: 137271 bytes + +Concurrency Level: 1 +Time taken for tests: 3.444 seconds +Complete requests: 100 +Failed requests: 46 + (Connect: 0, Receive: 0, Length: 46, Exceptions: 0) +Total transferred: 13782190 bytes +HTML transferred: 13727790 bytes +Requests per second: 29.03 [#/sec] (mean) +Time per request: 34.441 [ms] (mean) +Time per request: 34.441 [ms] (mean, across all concurrent requests) +Transfer rate: 3907.84 [Kbytes/sec] received + +Connection Times (ms) + min mean[+/-sd] median max +Connect: 0 0 0.1 0 1 +Processing: 25 34 14.5 31 141 +Waiting: 25 34 14.5 31 141 +Total: 25 34 14.5 31 141 + +Percentage of the requests served within a certain time (ms) + 50% 31 + 66% 33 + 75% 35 + 80% 35 + 90% 46 + 95% 51 + 98% 96 + 99% 141 +100% 141 (longest request) +``` + +- `Rendering: stories/_main_stories_feed.html.er... 3.4 +18.5` + +## Результаты + +В результате проделанной оптимизации удалось ускорить время рендеринга `StoriesController#index` ~ в 1.5 раза. diff --git a/config/environments/local_production.rb b/config/environments/local_production.rb index 14a07806..b8913f16 100644 --- a/config/environments/local_production.rb +++ b/config/environments/local_production.rb @@ -24,18 +24,18 @@ def yarn_integrity_enabled? config.consider_all_requests_local = true # Enable/disable caching. By default caching is disabled. - # if Rails.root.join("tmp/caching-dev.txt").exist? + if Rails.root.join("tmp/caching-dev.txt").exist? config.action_controller.perform_caching = true config.cache_store = :memory_store config.public_file_server.headers = { "Cache-Control" => "public, max-age=172800" } - # else - # config.action_controller.perform_caching = false + else + config.action_controller.perform_caching = false - # config.cache_store = :null_store - # end + config.cache_store = :null_store + end # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false