From e904d396c8ae3e52be87d9935d7ea5bf187d6c11 Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Tue, 7 Jan 2025 15:02:35 +0100 Subject: [PATCH] Make sure cache jobs are run only on server start --- CHANGELOG.md | 6 ++++++ app/jobs/cache/preheating_job.rb | 6 +++++- app/models/user.rb | 24 ++++++++++++++++-------- app/services/cache/clean.rb | 5 +++++ app/services/imports/create.rb | 2 +- config/environment.rb | 11 +++++++---- spec/services/imports/create_spec.rb | 4 ++-- 7 files changed, 42 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1f8706b..3b2e1169 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # 0.21.6 - 2025-01-07 +### Changed + +- Disabled visit suggesting job after import. +- Improved performance of the `User#years_tracked` method. + ### Fixed - Inconsistent password for the `dawarich_db` service in `docker-compose_mounted_volumes.yml`. #605 - Points are now being rendered with higher z-index than polylines. #577 +- Run cache cleaning and preheating jobs only on server start. #594 # 0.21.5 - 2025-01-07 diff --git a/app/jobs/cache/preheating_job.rb b/app/jobs/cache/preheating_job.rb index bdf3ea99..c43a50b3 100644 --- a/app/jobs/cache/preheating_job.rb +++ b/app/jobs/cache/preheating_job.rb @@ -5,7 +5,11 @@ class Cache::PreheatingJob < ApplicationJob def perform User.find_each do |user| - Rails.cache.write("dawarich/user_#{user.id}_years_tracked", user.years_tracked, expires_in: 1.day) + Rails.cache.write( + "dawarich/user_#{user.id}_years_tracked", + user.years_tracked, + expires_in: 1.day + ) end end end diff --git a/app/models/user.rb b/app/models/user.rb index 64e45425..f0413f68 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -66,15 +66,23 @@ class User < ApplicationRecord def years_tracked Rails.cache.fetch("dawarich/user_#{id}_years_tracked", expires_in: 1.day) do - tracked_points - .pluck(:timestamp) - .map { |ts| Time.zone.at(ts) } - .group_by(&:year) - .transform_values do |dates| - dates.map { |date| date.strftime('%b') }.uniq.sort - end + # Use select_all for better performance with large datasets + sql = <<-SQL + SELECT DISTINCT + EXTRACT(YEAR FROM TO_TIMESTAMP(timestamp)) AS year, + TO_CHAR(TO_TIMESTAMP(timestamp), 'Mon') AS month + FROM points + WHERE user_id = #{id} + ORDER BY year DESC, month ASC + SQL + + result = ActiveRecord::Base.connection.select_all(sql) + + result + .map { |r| [r['year'].to_i, r['month']] } + .group_by { |year, _| year } + .transform_values { |year_data| year_data.map { |_, month| month } } .map { |year, months| { year: year, months: months } } - .sort_by { |entry| -entry[:year] } # Sort in descending order end end diff --git a/app/services/cache/clean.rb b/app/services/cache/clean.rb index 46a69e0b..15647b99 100644 --- a/app/services/cache/clean.rb +++ b/app/services/cache/clean.rb @@ -4,6 +4,7 @@ class Cache::Clean class << self def call Rails.logger.info('Cleaning cache...') + delete_control_flag delete_version_cache delete_years_tracked_cache Rails.logger.info('Cache cleaned') @@ -11,6 +12,10 @@ class Cache::Clean private + def delete_control_flag + Rails.cache.delete('cache_jobs_scheduled') + end + def delete_version_cache Rails.cache.delete(CheckAppVersion::VERSION_CACHE_KEY) end diff --git a/app/services/imports/create.rb b/app/services/imports/create.rb index af9b0d0c..16374170 100644 --- a/app/services/imports/create.rb +++ b/app/services/imports/create.rb @@ -14,7 +14,7 @@ class Imports::Create create_import_finished_notification(import, user) schedule_stats_creating(user.id) - schedule_visit_suggesting(user.id, import) + # schedule_visit_suggesting(user.id, import) # Disabled until places & visits are reworked rescue StandardError => e create_import_failed_notification(import, user, e) end diff --git a/config/environment.rb b/config/environment.rb index 7e5c58f9..9d36606c 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -6,8 +6,11 @@ require_relative 'application' # Initialize the Rails application. Rails.application.initialize! -# Clear the cache -Cache::CleaningJob.perform_later +# Use an atomic operation to ensure one-time execution +if defined?(Rails::Server) && Rails.cache.write('cache_jobs_scheduled', true, unless_exist: true) + # Clear the cache + Cache::CleaningJob.perform_later -# Preheat the cache -Cache::PreheatingJob.perform_later + # Preheat the cache + Cache::PreheatingJob.perform_later +end diff --git a/spec/services/imports/create_spec.rb b/spec/services/imports/create_spec.rb index 85f2131a..08b1c60d 100644 --- a/spec/services/imports/create_spec.rb +++ b/spec/services/imports/create_spec.rb @@ -50,7 +50,7 @@ RSpec.describe Imports::Create do end end - it 'schedules visit suggesting' do + xit 'schedules visit suggesting' do Sidekiq::Testing.inline! do expect { service.call }.to have_enqueued_job(VisitSuggestingJob) end @@ -59,7 +59,7 @@ RSpec.describe Imports::Create do context 'when import fails' do before do - allow(OwnTracks::ExportParser).to receive(:new).with(import, user.id).and_return(double(call: false)) + allow(OwnTracks::ExportParser).to receive(:new).with(import, user.id).and_raise(StandardError) end it 'creates a failed notification' do