Switch to soft deletion on leaderboards

This commit is contained in:
Max Wofford
2025-02-21 19:58:45 -05:00
parent e6d165c67d
commit 56e24ba736
9 changed files with 53 additions and 17 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,5 @@
class AddFinishedGeneratingAtToLeaderboards < ActiveRecord::Migration[8.0]
def change
add_column :leaderboards, :finished_generating_at, :datetime
end
end

View File

@@ -0,0 +1,5 @@
class RemoveStartDateUniqueIndexFromLeaderboards < ActiveRecord::Migration[8.0]
def change
remove_index :leaderboards, :start_date
end
end

View File

@@ -0,0 +1,5 @@
class AddDeletedAtToLeaderboards < ActiveRecord::Migration[8.0]
def change
add_column :leaderboards, :deleted_at, :datetime, null: true
end
end

5
db/schema.rb generated
View File

@@ -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|