Add missing tests and process reverse geocoding in batches

This commit is contained in:
Eugene Burmakin 2024-12-06 17:32:45 +01:00
parent b7e4a017b8
commit 3b115a85b1
13 changed files with 47 additions and 59 deletions

View file

@ -1 +1 @@
0.19.2
0.19.3

View file

@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
# 0.19.3 - 2024-12-06
### Changed
- Refactored stats calculation to calculate only necessary stats, instead of calculating all stats
- Stats are now being calculated every 1 hour instead of 6 hours
- List of years on the Map page is now being calculated based on user's points instead of stats. It's also being cached for 1 day due to the fact that it's usually a heavy operation based on the number of points.
- Reverse-geocoding points is now being performed in batches of 1,000 points to prevent memory exhaustion.
# 0.19.2 - 2024-12-04
## The Telemetry release

View file

@ -5,9 +5,7 @@ class Cache::PreheatingJob < ApplicationJob
def perform
User.find_each do |user|
Rails.cache.fetch("dawarich/user_#{user.id}_years_tracked", expires_in: 1.day) do
user.years_tracked
end
Rails.cache.write("dawarich/user_#{user.id}_years_tracked", user.years_tracked, expires_in: 1.day)
end
end
end

View file

@ -35,12 +35,6 @@ class Stat < ApplicationRecord
}
end
def self.years
starting_year = select(:year).min&.year || Time.current.year
(starting_year..Time.current.year).to_a.reverse
end
def points
user.tracked_points
.without_raw_data

View file

@ -21,6 +21,6 @@ class Jobs::Create
raise InvalidJobName, 'Invalid job name'
end
points.each(&:async_reverse_geocode)
points.find_each(batch_size: 1_000, &:async_reverse_geocode)
end
end

View file

@ -4,7 +4,7 @@
<div class="dropdown">
<div tabindex="0" role="button" class="btn">Select year</div>
<ul tabindex="0" class="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52">
<% current_user.stats.years.each do |year| %>
<% current_user.years_tracked.each do |year| %>
<li><%= link_to year, map_url(year_timespan(year).merge(year: year, import_id: params[:import_id])) %></li>
<% end %>
</ul>

View file

@ -40,7 +40,7 @@ Rails.application.routes.draw do
post 'notifications/mark_as_read', to: 'notifications#mark_as_read', as: :mark_notifications_as_read
resources :stats, only: :index do
collection do
post :update, constraints: { year: /\d{4}/, month: /\d{1,2}/ }
post :update
end
end
get 'stats/:year', to: 'stats#show', constraints: { year: /\d{4}/ }

View file

@ -1,7 +1,7 @@
# config/schedule.yml
bulk_stats_calculating_job:
cron: "0 */6 * * *" # every 6 hour
cron: "0 */1 * * *" # every 1 hour
class: "BulkStatsCalculatingJob"
queue: stats

16
db/schema.rb generated
View file

@ -198,21 +198,6 @@ ActiveRecord::Schema[7.2].define(version: 2024_12_05_160055) do
t.index ["user_id"], name: "index_trips_on_user_id"
end
create_table "user_digests", force: :cascade do |t|
t.bigint "user_id", null: false
t.integer "kind", default: 0, null: false
t.datetime "start_at", null: false
t.datetime "end_at"
t.integer "distance", default: 0, null: false
t.text "countries", default: [], array: true
t.text "cities", default: [], array: true
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["distance"], name: "index_user_digests_on_distance"
t.index ["kind"], name: "index_user_digests_on_kind"
t.index ["user_id"], name: "index_user_digests_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
@ -260,7 +245,6 @@ ActiveRecord::Schema[7.2].define(version: 2024_12_05_160055) do
add_foreign_key "points", "visits"
add_foreign_key "stats", "users"
add_foreign_key "trips", "users"
add_foreign_key "user_digests", "users"
add_foreign_key "visits", "areas"
add_foreign_key "visits", "places"
add_foreign_key "visits", "users"

View file

@ -1,5 +0,0 @@
require 'rails_helper'
RSpec.describe Cache::PreheatingJob, type: :job do
pending "add some examples to (or delete) #{__FILE__}"
end

View file

@ -22,4 +22,14 @@ RSpec.describe Import, type: :model do
)
end
end
describe '#years_and_months_tracked' do
let(:import) { create(:import) }
let(:timestamp) { Time.zone.local(2024, 11, 1) }
let!(:points) { create_list(:point, 3, import:, timestamp:) }
it 'returns years and months tracked' do
expect(import.years_and_months_tracked).to eq([[2024, 11]])
end
end
end

View file

@ -51,30 +51,6 @@ RSpec.describe Stat, type: :model do
end
end
describe '.years' do
subject { described_class.years }
context 'when there are no stats' do
it 'returns years' do
expect(subject).to eq([Time.current.year])
end
end
context 'when there are stats' do
let(:user) { create(:user) }
let(:expected_years) { (year..Time.current.year).to_a.reverse }
before do
create(:stat, year: 2021, user:)
create(:stat, year: 2020, user:)
end
it 'returns years' do
expect(subject).to eq(expected_years)
end
end
end
describe '#distance_by_day' do
subject { stat.distance_by_day }
@ -146,5 +122,17 @@ RSpec.describe Stat, type: :model do
end
end
end
describe '#points' do
subject { stat.points.to_a }
let(:stat) { create(:stat, year:, month: 1, user:) }
let(:timestamp) { DateTime.new(year, 1, 1, 5, 0, 0) }
let!(:points) { create_list(:point, 3, user:, timestamp:) }
it 'returns points' do
expect(subject).to eq(points)
end
end
end
end

View file

@ -104,5 +104,15 @@ RSpec.describe User, type: :model do
expect(subject).to eq(1)
end
end
describe '#years_tracked' do
let!(:points) { create_list(:point, 3, user:, timestamp: DateTime.new(2024, 1, 1, 5, 0, 0)) }
subject { user.years_tracked }
it 'returns years tracked' do
expect(subject).to eq([2024])
end
end
end
end