From 56e24ba736d96946e60d52fd37be3549a5c3c971 Mon Sep 17 00:00:00 2001 From: Max Wofford Date: Fri, 21 Feb 2025 19:58:45 -0500 Subject: [PATCH] Switch to soft deletion on leaderboards --- app/avo/resources/leaderboard.rb | 16 ++++++++++++++ .../avo/leaderboards_controller.rb | 4 ++++ app/controllers/leaderboards_controller.rb | 2 +- app/jobs/leaderboard_update_job.rb | 22 ++++++++----------- app/models/leaderboard.rb | 6 ++++- ..._finished_generating_at_to_leaderboards.rb | 5 +++++ ...art_date_unique_index_from_leaderboards.rb | 5 +++++ ...22005401_add_deleted_at_to_leaderboards.rb | 5 +++++ db/schema.rb | 5 +++-- 9 files changed, 53 insertions(+), 17 deletions(-) create mode 100644 app/avo/resources/leaderboard.rb create mode 100644 app/controllers/avo/leaderboards_controller.rb create mode 100644 db/migrate/20250222002320_add_finished_generating_at_to_leaderboards.rb create mode 100644 db/migrate/20250222004511_remove_start_date_unique_index_from_leaderboards.rb create mode 100644 db/migrate/20250222005401_add_deleted_at_to_leaderboards.rb diff --git a/app/avo/resources/leaderboard.rb b/app/avo/resources/leaderboard.rb new file mode 100644 index 0000000..e1ff07d --- /dev/null +++ b/app/avo/resources/leaderboard.rb @@ -0,0 +1,16 @@ +class Avo::Resources::Leaderboard < Avo::BaseResource + def fields + field :id, as: :id + field :start_date, as: :date + field :finished_generating_at, as: :date_time + field :has_generated, as: :boolean do + record.finished_generating_at.present? + end + field :entries_count, as: :number do + record.entries.count + end + field :deleted, as: :boolean do + record.deleted_at.present? + end + end +end diff --git a/app/controllers/avo/leaderboards_controller.rb b/app/controllers/avo/leaderboards_controller.rb new file mode 100644 index 0000000..1219830 --- /dev/null +++ b/app/controllers/avo/leaderboards_controller.rb @@ -0,0 +1,4 @@ +# This controller has been generated to enable Rails' resource routes. +# More information on https://docs.avohq.io/3.0/controllers.html +class Avo::LeaderboardsController < Avo::ResourcesController +end diff --git a/app/controllers/leaderboards_controller.rb b/app/controllers/leaderboards_controller.rb index 882c916..a28cf43 100644 --- a/app/controllers/leaderboards_controller.rb +++ b/app/controllers/leaderboards_controller.rb @@ -1,6 +1,6 @@ class LeaderboardsController < ApplicationController def index - @leaderboard = Leaderboard.find_by(start_date: Date.current) + @leaderboard = Leaderboard.find_by(start_date: Date.current, deleted_at: nil) if @leaderboard.nil? LeaderboardUpdateJob.perform_later diff --git a/app/jobs/leaderboard_update_job.rb b/app/jobs/leaderboard_update_job.rb index 0f7fda5..1008e37 100644 --- a/app/jobs/leaderboard_update_job.rb +++ b/app/jobs/leaderboard_update_job.rb @@ -11,19 +11,14 @@ class LeaderboardUpdateJob < ApplicationJob drop: true ) - def perform(date = nil, leaderboard = nil) - if !leaderboard - date ||= Date.current - leaderboard = Leaderboard.find_or_initialize_by(start_date: date) - end + def perform(date = Date.current) + leaderboard = Leaderboard.create!(start_date: date) # Get list of valid user IDs from our database valid_user_ids = User.pluck(:slack_uid) return if valid_user_ids.empty? ActiveRecord::Base.transaction do - LeaderboardEntry.where(leaderboard: leaderboard).delete_all - valid_user_ids.each_slice(BATCH_SIZE) do |batch_user_ids| user_durations = Heartbeat.connection.select_all(<<-SQL).to_a WITH time_diffs AS ( @@ -52,9 +47,7 @@ class LeaderboardUpdateJob < ApplicationJob { leaderboard_id: leaderboard.id, user_id: row["user_id"], - total_seconds: row["total_seconds"], - created_at: Time.current, - updated_at: Time.current + total_seconds: row["total_seconds"] } end @@ -63,9 +56,12 @@ class LeaderboardUpdateJob < ApplicationJob end end - # Touch the leaderboard after all batches are processed - leaderboard.touch(:updated_at) unless leaderboard.new_record? - leaderboard.save! if leaderboard.new_record? + # Set finished_generating_at after successful completion + leaderboard.finished_generating_at = Time.current + leaderboard.save! + + # Delete previous leaderboard entries from today + Leaderboard.where.not(id: leaderboard.id).where(start_date: date).where(deleted_at: nil).update_all(deleted_at: Time.current) rescue => e Rails.logger.error "Failed to update current leaderboard: #{e.message}" raise diff --git a/app/models/leaderboard.rb b/app/models/leaderboard.rb index 77933f9..185c9ad 100644 --- a/app/models/leaderboard.rb +++ b/app/models/leaderboard.rb @@ -3,5 +3,9 @@ class Leaderboard < ApplicationRecord class_name: "LeaderboardEntry", dependent: :destroy - validates :start_date, presence: true, uniqueness: true + validates :start_date, presence: true + + def finished_generating? + finished_generating_at.present? + end end diff --git a/db/migrate/20250222002320_add_finished_generating_at_to_leaderboards.rb b/db/migrate/20250222002320_add_finished_generating_at_to_leaderboards.rb new file mode 100644 index 0000000..2091035 --- /dev/null +++ b/db/migrate/20250222002320_add_finished_generating_at_to_leaderboards.rb @@ -0,0 +1,5 @@ +class AddFinishedGeneratingAtToLeaderboards < ActiveRecord::Migration[8.0] + def change + add_column :leaderboards, :finished_generating_at, :datetime + end +end diff --git a/db/migrate/20250222004511_remove_start_date_unique_index_from_leaderboards.rb b/db/migrate/20250222004511_remove_start_date_unique_index_from_leaderboards.rb new file mode 100644 index 0000000..c2e5f5a --- /dev/null +++ b/db/migrate/20250222004511_remove_start_date_unique_index_from_leaderboards.rb @@ -0,0 +1,5 @@ +class RemoveStartDateUniqueIndexFromLeaderboards < ActiveRecord::Migration[8.0] + def change + remove_index :leaderboards, :start_date + end +end diff --git a/db/migrate/20250222005401_add_deleted_at_to_leaderboards.rb b/db/migrate/20250222005401_add_deleted_at_to_leaderboards.rb new file mode 100644 index 0000000..3e57bad --- /dev/null +++ b/db/migrate/20250222005401_add_deleted_at_to_leaderboards.rb @@ -0,0 +1,5 @@ +class AddDeletedAtToLeaderboards < ActiveRecord::Migration[8.0] + def change + add_column :leaderboards, :deleted_at, :datetime, null: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 857db55..c1533b4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2025_02_21_224605) do +ActiveRecord::Schema[8.0].define(version: 2025_02_22_005401) do # These are extensions that must be enabled in order to support this database enable_extension "pg_catalog.plpgsql" @@ -118,7 +118,8 @@ ActiveRecord::Schema[8.0].define(version: 2025_02_21_224605) do t.date "start_date", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.index ["start_date"], name: "index_leaderboards_on_start_date", unique: true + t.datetime "finished_generating_at" + t.datetime "deleted_at" end create_table "users", force: :cascade do |t|