Skip to content
Open

dz4 #118

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ latest.dump
/public/packs-test
/node_modules
config/database.yml
config/newrelic.yml

# Ignore storybook static site generation
storybook-static/
Expand Down
2 changes: 2 additions & 0 deletions Envfile
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ variable :TRENDING_TAGS, :String, default: "git,beginners"
variable :FACEBOOK_PIXEL_ID, :String, default: "Optional"
variable :SMARTY_STREETS_WEB_KEY, :String, default: "Optional"

# Skylight
variable :SKYLIGHT_AUTHENTICATION, :String, default: "Optional"

group :production do
variable :SECRET_KEY_BASE, :String
Expand Down
6 changes: 5 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ git_source(:github) do |repo_name|
"https://github.com/#{repo_name}.git"
end

group :production do
group :production, :local_production do
gem "nakayoshi_fork"
end

Expand Down Expand Up @@ -102,6 +102,9 @@ gem "uglifier", "~> 4.1"
gem "validate_url", "~> 1.0"
gem "webpacker", "~> 3.5"
gem "webpush", "~> 0.3"
gem "newrelic_rpm"
gem "prometheus_exporter"
gem "rack-mini-profiler"

group :development do
gem "better_errors", "~> 2.5"
Expand All @@ -115,6 +118,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
Expand Down
15 changes: 15 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,9 @@ GEM
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
memory_profiler (0.9.12)
meta_request (0.7.3)
rack-contrib (>= 1.1, < 3)
railties (>= 3.0.0, < 7)
method_source (0.9.2)
mime-types (3.2.2)
mime-types-data (~> 3.2015)
Expand All @@ -612,6 +615,7 @@ GEM
net-http-persistent (3.0.0)
connection_pool (~> 2.2)
netrc (0.11.0)
newrelic_rpm (8.9.0)
nio4r (2.3.1)
nokogiri (1.10.1)
mini_portile2 (~> 2.4.0)
Expand Down Expand Up @@ -651,6 +655,8 @@ GEM
ast (~> 2.4.0)
pg (1.1.4)
powerpack (0.1.2)
prometheus_exporter (2.0.3)
webrick
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
Expand All @@ -675,8 +681,12 @@ GEM
pusher-signature (0.1.8)
raabro (1.1.6)
rack (2.0.6)
rack-contrib (2.3.0)
rack (~> 2.0)
rack-host-redirect (1.3.0)
rack
rack-mini-profiler (3.0.0)
rack (>= 1.2.0)
rack-protection (2.0.4)
rack
rack-proxy (0.6.5)
Expand Down Expand Up @@ -932,6 +942,7 @@ GEM
webpush (0.3.2)
hkdf (~> 0.2)
jwt
webrick (1.7.0)
websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.3)
Expand Down Expand Up @@ -1012,14 +1023,17 @@ DEPENDENCIES
libhoney (~> 1.11)
liquid (~> 4.0)
memory_profiler (~> 0.9)
meta_request
nakayoshi_fork
newrelic_rpm
nokogiri (~> 1.10)
octokit (~> 4.13)
omniauth (~> 1.9)
omniauth-github (~> 1.3)
omniauth-twitter (~> 1.4)
parallel_tests (~> 2.27)
pg (~> 1.1)
prometheus_exporter
pry (~> 0.12)
pry-byebug (~> 3.7)
pry-rails (~> 0.3)
Expand All @@ -1029,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)!
Expand Down
1 change: 1 addition & 0 deletions Procfile.dev
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
web: bin/rails s -p 3000
webpacker: ./bin/webpack-dev-server
job: bin/rake jobs:work
prometheus_exporter: bundle exec prometheus_exporter -a prometheus/custom-collector.rb
10 changes: 6 additions & 4 deletions app/views/stories/_main_stories_feed.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,13 @@
<% 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" %>
<% cache story do %>
<% next if story.id == @featured_story.id %>
<% if !user_signed_in? && i == 4 %>
<%= render "stories/sign_in_invitation" %>
<% end %>
<%= render "articles/single_story", story: story %>
<% end %>
<%= render "articles/single_story", story: story %>
<% end %>
<% end %>
<% if @stories.size > 1 %>
Expand Down
19 changes: 19 additions & 0 deletions bin/startup_lp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env ruby
require "pathname"
require "fileutils"
include FileUtils

# path to your application root.
APP_ROOT = Pathname.new File.expand_path("..", __dir__)

def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==")
end

chdir APP_ROOT do
puts "== ASSETS PRECOMPILE =="
system! "bin/rails assets:precompile"

puts "== STARTING UP =="
system! "RAILS_ENV=local_production bin/rails s"
end
55 changes: 55 additions & 0 deletions case-study.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Rails Optimization - HW4

### 1. Завести dev.to локально

Пробую запустить проект по инструкции из `README`.

Возникли ошибки при `yarn install`, помог запуск `yarn upgrade`. Старые миграции не проходили, пришлось указать версию в наследовании `ActiveRecord::Migration[4.2]`.

После этого проект успешно запустился, но база была пустая, запустил `db:seed`. Всё завелось)

### 2. Настроить свой NewRelic для мониторинга локального dev.to

Зарегистрировался в New Relic, скачал конфиг, установил гем, данные начали появляться в New Relic. Файл конфига добавил в гит игнор.

### 3. Настроить свой Skylight / Scout / Datadog для мониторинга локального dev.to

Зарегистрировался в Skylight, так как он уже настроен в проекте через ENV переменную, решил так и оставить, просто добавить эту переменную в `Envfile` и `config/application.yml`.

В Skylight появилось только окружение `production`, поэтому я добавил `development` в конфиге `application.rb`.

### 4. Настроить свой Prometheus + Grafana для мониторинга локального dev.to

Добавил гем `prometheus_exporter`, ещё раз изучил и скопировал конфиги `docker-compose.yml`, `prometheus.yml`. Также решил добавить и `custom-collector.rb`, чтобы потренироваться с кастомными метриками. Добавил инишиалайзер, обновил `Procfile.dev`.

Запустил приложение, запустил докер с прометеусом и графаной, потыкал в прометеусе, зашел под админом в графану, добавил дата соурс, попробовал настроить дашборд. Всё получилось.

### 5. Настроить rack-mini-profiler

Добавил гем, rmp поднялся.

### 6. Настроить rails-panel

Добавил гем `meta_request`, Rails Panel поднялась.

### 7. Сделать возможность запуска проекта в local_production

Скопировал конфиг `development.rb` и изменил настройки под `local_production`, дополнил все настройки новой средой `local_production`. Создал файл `tmp/caching-dev.txt`. Добавил скрипт запуска `bin/startup_lp` с компиляцией ассетов.

Возникла ошибка таймаута, поэтому увеличил время таймаута для среды `local_production`.

### 8. Оптимизация

Сделал замеры до и после добавления кеширования, как итог скорость загрузки увеличилась примерно в 2 раза.

100 запросов с помощью команды `ab` без кеширования выполнялись за 9-10 секунд, после добавления кеширования за 4-5.

### Итог

Я попрактиковался в настройке и использовании разных систем мониторинга, попробовал как SaaS, так и DIY решения. Еще раз попробовал `rmp` и `rails-panel`, закрепил навыки.

Настроил среду `local_production`, в которой можно намного точнее замерять, профилировать и находить точки роста, которые возникают на проде. Также внедрю эту среду и в своих проектах, так как уже иногда возникала необходимость запускать продакшн локально и воспроизводить проблемы, как на проде, например с ассетами.

Попробовал инструмент `ab`, на мой взгляд, самый простой и быстрый для замера скорости загрузки страниц и понимания эффективности оптимизаций. Удобно использовать в фидбек-лупе, так как быстро даёт обратную связь по проделанным изменениям.

Добавил небольшую оптимизацию на главную страницу с помощью кеширования, оценил на конкретных цифрах какой эффект даёт кеширование фрагмента.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Отлично, всё то что надо! 👍

2 changes: 2 additions & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,7 @@ class Application < Rails::Application
end
ReservedWords.all = [ReservedWords::BASE_WORDS + top_routes].flatten.compact.uniq
end

config.skylight.environments += %w[development local_production]
end
end
107 changes: 107 additions & 0 deletions config/environments/local_production.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# 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

config.action_controller.asset_host = 'http://localhost:3000'

# 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 = :debug

# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load

# Compress JavaScripts and CSS.
config.assets.js_compressor = Uglifier.new(harmony: true)

# 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

# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = true

# 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

# 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.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
2 changes: 1 addition & 1 deletion config/initializers/airbrake.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
# environments.
# NOTE: This option *does not* work if you don't set the 'environment' option.
# https://github.com/airbrake/airbrake-ruby#ignore_environments
c.ignore_environments = %w[test development]
c.ignore_environments = %w[test development local_production]

# A list of parameters that should be filtered out of what is sent to
# Airbrake. By default, all "password" attributes will have their contents
Expand Down
2 changes: 1 addition & 1 deletion config/initializers/carrierwave.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
require "carrierwave/storage/fog"

CarrierWave.configure do |config|
if Rails.env.development? || Rails.env.test?
if Rails.env.development? || Rails.env.local_production? || Rails.env.test?
config.storage = :file
else
# config.fog_provider = 'fog-aws'
Expand Down
7 changes: 7 additions & 0 deletions config/initializers/prometheus.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# config/initializers/prometheus.rb
if Rails.env != "test"
require 'prometheus_exporter/middleware'

# This reports stats per request like HTTP status and timings
Rails.application.middleware.unshift PrometheusExporter::Middleware
end
2 changes: 1 addition & 1 deletion config/initializers/reverse_markdown.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Because files are eagerloaded in production, this fix is only
# applicable in development (and test, when needed)

if Rails.env.development? || Rails.env.test?
if Rails.env.development? || Rails.env.local_production? || Rails.env.test?
Rails.application.config.to_prepare do
Dir.glob(Rails.root.join("app/lib/reverse_markdown/converters/*.rb")).sort.each do |filename|
require_dependency filename
Expand Down
2 changes: 1 addition & 1 deletion config/initializers/timeout.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
if Rails.env.development? && ENV["RACK_TIMEOUT_WAIT_TIMEOUT"].nil?
if (Rails.env.development? || Rails.env.local_production?) && ENV["RACK_TIMEOUT_WAIT_TIMEOUT"].nil?
ENV["RACK_TIMEOUT_WAIT_TIMEOUT"] = "100000"
ENV["RACK_TIMEOUT_SERVICE_TIMEOUT"] = "100000"
end
Expand Down
4 changes: 3 additions & 1 deletion config/secrets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
# Make sure the secrets in this file are kept private
# if you're sharing your code publicly.

development:
development: &development
secret_key_base: a60edc976c913b19fd9fc8118936fbe1df2b07f4eecc5ad32f975e33cd4ea36b150c1ce933b681b90874a46568041629003dcbfc07238f7dca91741bcd1ec870

test:
secret_key_base: 42dd7834039ebbea271af22635a6782ee15e519b14629c5276bfcdd4cff841e9926994784bb43a335a8f8c9739bb254ea3afe831839d4dc65654ec7516ec25f0

local_production:
<<: *development

# Do not keep production secrets in the repository,
# instead read values from the environment.
Expand Down
Loading