diff --git a/.app_version b/.app_version
index 61e6e92d..b72b05ed 100644
--- a/.app_version
+++ b/.app_version
@@ -1 +1 @@
-0.19.2
+0.19.3
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 88b0a520..b67dd939 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/app/jobs/cache/preheating_job.rb b/app/jobs/cache/preheating_job.rb
index 75353ed8..bdf3ea99 100644
--- a/app/jobs/cache/preheating_job.rb
+++ b/app/jobs/cache/preheating_job.rb
@@ -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
diff --git a/app/models/stat.rb b/app/models/stat.rb
index 8bfe5b36..9376c991 100644
--- a/app/models/stat.rb
+++ b/app/models/stat.rb
@@ -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
diff --git a/app/services/jobs/create.rb b/app/services/jobs/create.rb
index fdefe62d..ff8466be 100644
--- a/app/services/jobs/create.rb
+++ b/app/services/jobs/create.rb
@@ -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
diff --git a/app/views/shared/_right_sidebar.html.erb b/app/views/shared/_right_sidebar.html.erb
index 87c99c04..797adaeb 100644
--- a/app/views/shared/_right_sidebar.html.erb
+++ b/app/views/shared/_right_sidebar.html.erb
@@ -4,7 +4,7 @@
Select year
- <% current_user.stats.years.each do |year| %>
+ <% current_user.years_tracked.each do |year| %>
- <%= link_to year, map_url(year_timespan(year).merge(year: year, import_id: params[:import_id])) %>
<% end %>
diff --git a/config/routes.rb b/config/routes.rb
index 7639ce4b..2c40e93d 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -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}/ }
diff --git a/config/schedule.yml b/config/schedule.yml
index 08de79bd..e27337d6 100644
--- a/config/schedule.yml
+++ b/config/schedule.yml
@@ -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
diff --git a/db/schema.rb b/db/schema.rb
index fea44510..2927e2d5 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -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"
diff --git a/spec/jobs/cache/preheating_job_spec.rb b/spec/jobs/cache/preheating_job_spec.rb
deleted file mode 100644
index 3180c856..00000000
--- a/spec/jobs/cache/preheating_job_spec.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe Cache::PreheatingJob, type: :job do
- pending "add some examples to (or delete) #{__FILE__}"
-end
diff --git a/spec/models/import_spec.rb b/spec/models/import_spec.rb
index 2e04a91d..d6c7efc8 100644
--- a/spec/models/import_spec.rb
+++ b/spec/models/import_spec.rb
@@ -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
diff --git a/spec/models/stat_spec.rb b/spec/models/stat_spec.rb
index 369a8e87..ae65afd2 100644
--- a/spec/models/stat_spec.rb
+++ b/spec/models/stat_spec.rb
@@ -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
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index c42d969f..adaf50cd 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -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