demarches-normaliennes/app/services/notification_service.rb
Pierre de La Morinerie 0e35bc609d notifications: don't preload dossiers on instructeurs
This request currently times out almost every night in production.

It's because although Instructeurs are loaded in batches (default batch
size is 1000), loading all dossiers for 1000 instructeurs is slow.

Turns out the code executed after this query to compute notifications
doesn't even use these dossiers. Indeed it is faster not to preload
them: both the initial query and the total treatment time are shorter.

Here's a quick benchmark made locally (but using production data):

- Before this commit:

	Benchmark.measure { pp Instructeur.includes(assign_to: { procedure: :dossiers }).where(assign_tos: { daily_email_notifications_enabled: true }).limit(100).m
ap(&:email_notification_data) }

Only the initial query : 35s
Total time : 97s

- Without preloading dossiers:

	Benchmark.measure { pp Instructeur.includes(assign_to: :procedure).where(assign_tos: { daily_email_notifications_enabled: true }).limit(100).m
ap(&:email_notification_data) }

Only the initial query : 0.08s (400x faster)
Total time : 29s (3,3x faster)

Plus it doesn't timeout, of course.
2021-12-09 12:10:00 +01:00

19 lines
697 B
Ruby

class NotificationService
class << self
def send_instructeur_email_notification
Instructeur
.includes(assign_to: [:procedure])
.where(assign_tos: { daily_email_notifications_enabled: true })
.find_in_batches { |instructeurs| send_batch_of_instructeurs_email_notification(instructeurs) }
end
private
def send_batch_of_instructeurs_email_notification(instructeurs)
instructeurs
.map { |instructeur| [instructeur, instructeur.email_notification_data] }
.reject { |(_instructeur, data)| data.empty? }
.each { |(instructeur, data)| InstructeurMailer.send_notifications(instructeur, data).deliver_later }
end
end
end