All Projects β†’ charkost β†’ Prosopite

charkost / Prosopite

Licence: apache-2.0
πŸ” Rails N+1 queries auto-detection with zero false positives / false negatives

Programming Languages

ruby
36898 projects - #4 most used programming language

Projects that are alternatives of or similar to Prosopite

Bootscale
Speedup applications boot by caching require calls
Stars: ✭ 190 (-65.77%)
Mutual labels:  rails, performance
Active record doctor
Identify database issues before they hit production.
Stars: ✭ 865 (+55.86%)
Mutual labels:  rails, performance
Rails performance
Monitor performance of you Rails applications
Stars: ✭ 345 (-37.84%)
Mutual labels:  rails, performance
Execution time
How fast is your code? See it directly in Rails console.
Stars: ✭ 67 (-87.93%)
Mutual labels:  rails, performance
Timeasure
Transparent method-level wrapper for profiling purposes in Ruby
Stars: ✭ 192 (-65.41%)
Mutual labels:  rails, performance
Query track
Find time-consuming database queries for ActiveRecord-based RailsΒ Apps
Stars: ✭ 258 (-53.51%)
Mutual labels:  rails, performance
App perf
Open source application performance monitoring tool with emphasis on ease of setup and use. Providing similar functionality like NewRelic/AppNeta/Skylight etc.
Stars: ✭ 353 (-36.4%)
Mutual labels:  rails, performance
Bigcache
Efficient cache for gigabytes of data written in Go.
Stars: ✭ 5,304 (+855.68%)
Mutual labels:  performance
Profiler
Firefox Profiler β€” Web app for Firefox performance analysis
Stars: ✭ 546 (-1.62%)
Mutual labels:  performance
Laravel Binary Uuid
Optimised binary UUIDs in Laravel
Stars: ✭ 523 (-5.77%)
Mutual labels:  performance
Fuzzapi
Fuzzapi is a tool used for REST API pentesting and uses API_Fuzzer gem
Stars: ✭ 521 (-6.13%)
Mutual labels:  rails
Activerecord Multi Tenant
Rails/ActiveRecord support for distributed multi-tenant databases like Postgres+Citus
Stars: ✭ 526 (-5.23%)
Mutual labels:  rails
Cancancan
The authorization Gem for Ruby on Rails.
Stars: ✭ 5,046 (+809.19%)
Mutual labels:  rails
Rails email preview
Preview and edit app mailer templates in Rails.
Stars: ✭ 524 (-5.59%)
Mutual labels:  rails
Bloom
🌸 HTTP REST API caching middleware, to be used between load balancers and REST API workers.
Stars: ✭ 553 (-0.36%)
Mutual labels:  performance
Active storage validations
Do it like => validates :photos, attached: true, content_type: ['image/png', 'image/jpg', 'image/jpeg'], size: { less_than: 500.kilobytes }, limit: { min: 1, max: 3 }, aspect_ratio: :landscape, dimension: { width: { in: 800..1600 }
Stars: ✭ 522 (-5.95%)
Mutual labels:  rails
Entitas Csharp
Entitas is a super fast Entity Component System (ECS) Framework specifically made for C# and Unity
Stars: ✭ 5,393 (+871.71%)
Mutual labels:  performance
Automon
Automon combines the power of AOP (AspectJ) with monitoring or logging tools you already use to declaratively monitor your Java code, the JDK, and 3rd party libraries.
Stars: ✭ 548 (-1.26%)
Mutual labels:  performance
Annict
The platform for anime addicts built with Rails and Stimulus.js.
Stars: ✭ 542 (-2.34%)
Mutual labels:  rails
React Esi
React ESI: Blazing-fast Server-Side Rendering for React and Next.js
Stars: ✭ 537 (-3.24%)
Mutual labels:  performance

Prosopite CI Gem Version

Prosopite is able to auto-detect Rails N+1 queries with zero false positives / false negatives.

N+1 queries detected:
  SELECT `users`.* FROM `users` WHERE `users`.`id` = 20 LIMIT 1
  SELECT `users`.* FROM `users` WHERE `users`.`id` = 21 LIMIT 1
  SELECT `users`.* FROM `users` WHERE `users`.`id` = 22 LIMIT 1
  SELECT `users`.* FROM `users` WHERE `users`.`id` = 23 LIMIT 1
  SELECT `users`.* FROM `users` WHERE `users`.`id` = 24 LIMIT 1
Call stack:
  app/controllers/thank_you_controller.rb:4:in `block in index'
  app/controllers/thank_you_controller.rb:3:in `each'
  app/controllers/thank_you_controller.rb:3:in `index':
  app/controllers/application_controller.rb:8:in `block in <class:ApplicationController>'

The need for prosopite emerged after dealing with various false positives / negatives using the bullet gem.

Compared to Bullet

Prosopite can auto-detect the following extra cases of N+1 queries:

N+1 queries after record creations (usually in tests)

FactoryBot.create_list(:leg, 10)

Leg.last(10).each do |l|
  l.chair
end

Not triggered by ActiveRecord associations

Leg.last(4).each do |l|
  Chair.find(l.chair_id)
end

First/last/pluck of collection associations

Chair.last(20).each do |c|
  c.legs.first
  c.legs.last
  c.legs.pluck(:id)
end

Changing the ActiveRecord class with #becomes

Chair.last(20).map{ |c| c.becomes(ArmChair) }.each do |ac|
  ac.legs.map(&:id)
end

Mongoid models calling ActiveRecord

class Leg::Design
  include Mongoid::Document
  ...
  field :cid, as: :chair_id, type: Integer
  ...
  def chair
    @chair ||= Chair.where(id: chair_id).first!
  end
end

Leg::Design.last(20) do |l|
  l.chair
end

Why a new gem

Creating a new gem makes more sense since bullet's core mechanism is completely different from prosopite's.

How it works

Prosopite monitors all SQL queries using the Active Support instrumentation and looks for the following pattern which is present in all N+1 query cases:

More than one queries have the same call stack and the same query fingerprint.

Installation

Add this line to your application's Gemfile:

gem 'prosopite'

If you're not using MySQL/MariaDB, you should also add:

gem 'pg_query'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install prosopite

Configuration

The preferred type of notifications can be configured with:

  • Prosopite.rails_logger = true: Send warnings to the Rails log
  • Prosopite.prosopite_logger = true: Send warnings to log/prosopite.log
  • Prosopite.stderr_logger = true: Send warnings to STDERR
  • Prosopite.raise = true: Raise warnings as exceptions

Development Environment Usage

Prosopite auto-detection can be enabled on all controllers:

class ApplicationController < ActionController::Base
  unless Rails.env.production?
    before_action do
      Prosopite.scan
    end

    after_action do
      Prosopite.finish
    end
  end
end

And the preferred notification channel should be configured:

# config/environments/development.rb

config.after_initialize do
  Prosopite.rails_logger = true
end

Test Environment Usage

Tests with N+1 queries can be configured to fail with:

# config/environments/test.rb

config.after_initialize do
  Prosopite.rails_logger = true
  Prosopite.raise = true
end

And each test can be scanned with:

# spec/spec_helper.rb

config.before(:each) do
  Prosopite.scan
end

config.after(:each) do
  Prosopite.finish
end

WARNING: scan/finish should run before/after each test and NOT before/after the whole suite.

Allow list

Ignore notifications for call stacks containing one or more substrings:

Prosopite.allow_list = ['substring_in_call_stack']

Scanning code outside controllers or tests

All you have to do is to wrap the code with:

Prosopite.scan
<code to scan>
Prosopite.finish

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/charkost/prosopite.

License

Prosopite is licensed under the Apache License, Version 2.0. See LICENSE.txt for the full license text.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].