Supervisors and volunteers pages load every case contact in the org (13s requests, memory spikes)

Cerrado
#7,279 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
58/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
rails, ruby

Línea de trabajo

Start with app/policies/supervisor_policy.rb and app/models/user.rb, then trace how app/views/supervisors/index.html.erb uses volunteer counts. Run the policy and system specs named in the issue; use the suggested console data and compare query counts for both pages. Done means the pages avoid loading every contact and the N+1 queries, while the existing counts and specs remain unchanged.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

📈 Performance Improvement Help Wanted

Problem

/supervisors and /volunteers are the slowest pages in production. They also allocate the most memory, which likely contributes to the R14 memory errors in #7218.

From Scout APM, last 7 days:

Endpoint Avg response Slowest trace Allocations
supervisors/index 3.5 s 13.4 s ~800k
volunteers/index 1.2 s 13.8 s ~600k

In both slow traces, one preload query takes 12–13 s and loads ~29,600 CaseContact rows. That's every case contact written by every volunteer in the org, loaded on every page view.

Root cause

app/policies/supervisor_policy.rb:

class Scope < ApplicationPolicy::Scope
  def resolve
    scope.includes(
      :volunteers,
      volunteers: [:supervisor, :case_assignments, :case_contacts]
    )
  end
end

The preload doesn't even help:

  • /volunteers (VolunteersController#index, line ~11) only uses @supervisors for the supervisor filter dropdown and its ids. It never touches contacts.
  • /supervisors calls Supervisor#no_attempt_for_two_weeks (app/models/user.rb). That method calls volunteer.case_contacts.none? and volunteer.case_contacts.maximum(:created_at), which run fresh SQL anyway. The trace shows ~120 of each on top of the preload. It also runs SELECT * FROM case_assignments WHERE volunteer_id = ? 161 times, an N+1.

Suggested fix

  • Remove :case_contacts (and probably all the includes) from SupervisorPolicy::Scope#resolve. A policy scope should filter, not eager-load. Add the includes the page needs at the call site instead.
  • Rewrite no_attempt_for_two_weeks as one query per supervisor, or one grouped query for all supervisors. For example, count active volunteers with an active case assignment and no case_contacts created in the last 14 days. Use NOT EXISTS or MAX(created_at) grouped by creator_id, not Ruby loops.
  • Fix the case_assignments N+1 on /supervisors (volunteer.case_assignments.any?(&:active?) inside the loop).
  • Keep the existing spec/policies/supervisor_policy_spec.rb, spec/system/supervisors/index_spec.rb and spec/system/volunteers/index_spec.rb passing. The volunteer counts shown on /supervisors must not change.
  • Prosopite (N+1 detection) is already on in specs, so it will flag regressions.

How to verify locally

Seed data is small, so the slowness won't show up. Add a few thousand contacts in a console: FactoryBot.create_list(:case_contact, 3000, creator: Volunteer.first) in RAILS_ENV=development. Then compare the query count and time in the dev log before and after, for /supervisors and /volunteers as [email protected].

Difficulty: intermediate. It's mostly in two files (supervisor_policy.rb, user.rb), plus the views that read the counts (app/views/supervisors/index.html.erb).

Lenguaje dominante
Ruby
Estrellas
382
Forks
547
Merge medio
2 d 22 h
PR fusionados (30 d)
46

Preparar el entorno

Abrir en Codespaces

Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de rubyforgood/casa

Todos los issues de rubyforgood/casa

Issues similares

Más issues de Ruby

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.