Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ RSpec/MultipleMemoizedHelpers:
RSpec/NestedGroups:
Max: 7
RSpec/ExampleLength:
Max: 15
Max: 20
RSpec/MultipleExpectations:
Max: 5

Style/NumericLiterals:
Enabled: false
Expand Down Expand Up @@ -78,4 +80,4 @@ Style/HashTransformValues:

AllCops:
NewCops: enable
TargetRailsVersion: 4.2
TargetRailsVersion: 7.2
36 changes: 36 additions & 0 deletions app/workers/recents_cleanup_worker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

class RecentsCleanupWorker
include Sidekiq::Worker

sidekiq_options queue: :default,
retry: 0,
congestion: {
interval: 1.hour,
max_in_interval: 1,
reject_with: :cancel
}

def perform
Comment thread
zwolf marked this conversation as resolved.
# Delete all older than 90 days
Recent.where('created_at < ?', 90.days.ago).in_batches(of: 5000).delete_all

# Identify users active in the past 2 hours
recently_active_pairs = Recent.where('created_at > ?', 2.hours.ago)
.distinct
.pluck(:user_id, :project_id)

# Clean up any recents over 20 per user/project for recently active users
recently_active_pairs.each do |user_id, project_id|
scope = Recent.where(user_id: user_id, project_id: project_id)

next unless scope.count > 20

ids_to_keep = scope.order(created_at: :desc)
.limit(20)
.pluck(:id)

scope.where.not(id: ids_to_keep).delete_all
end
end
end
132 changes: 132 additions & 0 deletions db/migrate/20260428222525_delete_old_recents.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# frozen_string_literal: true

class DeleteOldRecents < ActiveRecord::Migration[7.2]
disable_ddl_transaction!

def up
Comment thread
zwolf marked this conversation as resolved.
safety_assured do
Comment thread
zwolf marked this conversation as resolved.
cutoff_date = 90.days.ago.to_fs(:db)
current_time = Time.current.to_fs(:db)

say 'Step 1: Creating new table from existing and loading recent recents...'

execute <<-SQL
Comment thread
zwolf marked this conversation as resolved.
CREATE TABLE recents_new (LIKE recents INCLUDING DEFAULTS INCLUDING CONSTRAINTS);

INSERT INTO recents_new
SELECT * FROM recents
WHERE created_at >= '#{cutoff_date}'
AND created_at < '#{current_time}';
SQL

say 'Step 2: Building indexes and FKs on new table with temporary names...'

execute 'ALTER TABLE recents_new ADD PRIMARY KEY (id);'

execute 'CREATE INDEX index_recents_new_on_workflow_id ON recents_new (workflow_id);'
execute 'CREATE INDEX index_recents_new_on_project_id ON recents_new (project_id);'
execute 'CREATE INDEX index_recents_new_on_user_id ON recents_new (user_id);'
execute 'CREATE INDEX index_recents_new_on_subject_id ON recents_new (subject_id);'
execute 'CREATE INDEX index_recents_new_on_created_at ON recents_new (created_at);'

# New compound index for user/project/created_at lookups
execute 'CREATE INDEX index_recents_on_user_project_and_created ON recents_new (user_id, project_id, created_at DESC);'

execute <<-SQL
Comment thread
zwolf marked this conversation as resolved.
ALTER TABLE recents_new
ADD CONSTRAINT fk_recents_classifications
FOREIGN KEY (classification_id) REFERENCES classifications(id);

ALTER TABLE recents_new
ADD CONSTRAINT fk_recents_subjects
FOREIGN KEY (subject_id) REFERENCES subjects(id);
SQL

say 'Step 3: Executing the table swap...'

execute <<-SQL
Comment thread
zwolf marked this conversation as resolved.
BEGIN;

-- Lock table prevent incoming writes
LOCK TABLE recents IN ACCESS EXCLUSIVE MODE;

-- Catch up any records created during above operations
INSERT INTO recents_new
SELECT * FROM recents
WHERE created_at >= '#{current_time}';

-- Swap the tables
ALTER TABLE recents RENAME TO recents_old;
ALTER TABLE recents_new RENAME TO recents;

-- Clean up index names so structure.sql looks untouched
ALTER INDEX recents_pkey RENAME TO recents_old_pkey;
ALTER INDEX recents_new_pkey RENAME TO recents_pkey;

ALTER INDEX index_recents_on_workflow_id RENAME TO index_recents_old_on_workflow_id;
ALTER INDEX index_recents_new_on_workflow_id RENAME TO index_recents_on_workflow_id;

ALTER INDEX index_recents_on_project_id RENAME TO index_recents_old_on_project_id;
ALTER INDEX index_recents_new_on_project_id RENAME TO index_recents_on_project_id;

ALTER INDEX index_recents_on_user_id RENAME TO index_recents_old_on_user_id;
ALTER INDEX index_recents_new_on_user_id RENAME TO index_recents_on_user_id;

ALTER INDEX index_recents_on_subject_id RENAME TO index_recents_old_on_subject_id;
ALTER INDEX index_recents_new_on_subject_id RENAME TO index_recents_on_subject_id;

ALTER INDEX index_recents_on_created_at RENAME TO index_recents_old_on_created_at;
ALTER INDEX index_recents_new_on_created_at RENAME TO index_recents_on_created_at;

-- Transfer sequence ownership
ALTER SEQUENCE recents_id_seq OWNED BY recents.id;

COMMIT;
SQL

say 'Step 4: Updating database statistics for the new table...'
execute 'ANALYZE recents;'

say 'Recents swap complete.'
end
end

def down
Comment thread
zwolf marked this conversation as resolved.
safety_assured do
execute <<-SQL
Comment thread
zwolf marked this conversation as resolved.
BEGIN;
LOCK TABLE recents IN ACCESS EXCLUSIVE MODE;

-- Swap tables back
ALTER TABLE recents RENAME TO recents_new;
ALTER TABLE recents_old RENAME TO recents;

-- Revert Sequence
ALTER SEQUENCE recents_id_seq OWNED BY recents.id;

-- Revert index names to original state
ALTER INDEX recents_pkey RENAME TO recents_new_pkey;
ALTER INDEX recents_old_pkey RENAME TO recents_pkey;

ALTER INDEX index_recents_on_workflow_id RENAME TO index_recents_new_on_workflow_id;
ALTER INDEX index_recents_old_on_workflow_id RENAME TO index_recents_on_workflow_id;

ALTER INDEX index_recents_on_project_id RENAME TO index_recents_new_on_project_id;
ALTER INDEX index_recents_old_on_project_id RENAME TO index_recents_on_project_id;

ALTER INDEX index_recents_on_user_id RENAME TO index_recents_new_on_user_id;
ALTER INDEX index_recents_old_on_user_id RENAME TO index_recents_on_user_id;

ALTER INDEX index_recents_on_subject_id RENAME TO index_recents_new_on_subject_id;
ALTER INDEX index_recents_old_on_subject_id RENAME TO index_recents_on_subject_id;

ALTER INDEX index_recents_on_created_at RENAME TO index_recents_new_on_created_at;
ALTER INDEX index_recents_old_on_created_at RENAME TO index_recents_on_created_at;

COMMIT;
SQL

execute 'DROP TABLE recents_new;'
end
end
end
93 changes: 89 additions & 4 deletions db/structure.sql
Original file line number Diff line number Diff line change
Expand Up @@ -1128,6 +1128,24 @@ CREATE SEQUENCE public.recents_id_seq
ALTER SEQUENCE public.recents_id_seq OWNED BY public.recents.id;


--
-- Name: recents_old; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.recents_old (
id integer DEFAULT nextval('public.recents_id_seq'::regclass) NOT NULL,
classification_id integer,
subject_id integer,
created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL,
project_id integer,
workflow_id integer,
user_id integer,
user_group_id integer,
mark_remove boolean DEFAULT false
);


--
-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: -
--
Expand Down Expand Up @@ -2495,6 +2513,14 @@ ALTER TABLE ONLY public.projects
ADD CONSTRAINT projects_pkey PRIMARY KEY (id);


--
-- Name: recents_old recents_old_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.recents_old
ADD CONSTRAINT recents_old_pkey PRIMARY KEY (id);


--
-- Name: recents recents_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
Expand Down Expand Up @@ -3231,6 +3257,41 @@ CREATE INDEX index_projects_on_state ON public.projects USING btree (state) WHER
CREATE INDEX index_projects_on_tsv ON public.projects USING gin (tsv);


--
-- Name: index_recents_old_on_created_at; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX index_recents_old_on_created_at ON public.recents_old USING btree (created_at);


--
-- Name: index_recents_old_on_project_id; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX index_recents_old_on_project_id ON public.recents_old USING btree (project_id);


--
-- Name: index_recents_old_on_subject_id; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX index_recents_old_on_subject_id ON public.recents_old USING btree (subject_id);


--
-- Name: index_recents_old_on_user_id; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX index_recents_old_on_user_id ON public.recents_old USING btree (user_id);


--
-- Name: index_recents_old_on_workflow_id; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX index_recents_old_on_workflow_id ON public.recents_old USING btree (workflow_id);


--
-- Name: index_recents_on_created_at; Type: INDEX; Schema: public; Owner: -
--
Expand All @@ -3252,6 +3313,13 @@ CREATE INDEX index_recents_on_project_id ON public.recents USING btree (project_
CREATE INDEX index_recents_on_subject_id ON public.recents USING btree (subject_id);


--
-- Name: index_recents_on_user_and_created; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX index_recents_on_user_and_created ON public.recents USING btree (user_id, created_at DESC);


--
-- Name: index_recents_on_user_id; Type: INDEX; Schema: public; Owner: -
--
Expand Down Expand Up @@ -3804,10 +3872,10 @@ ALTER TABLE ONLY public.gold_standard_annotations


--
-- Name: recents fk_rails_1e54468460; Type: FK CONSTRAINT; Schema: public; Owner: -
-- Name: recents_old fk_rails_1e54468460; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.recents
ALTER TABLE ONLY public.recents_old
ADD CONSTRAINT fk_rails_1e54468460 FOREIGN KEY (classification_id) REFERENCES public.classifications(id);


Expand Down Expand Up @@ -3884,10 +3952,10 @@ ALTER TABLE ONLY public.user_project_preferences


--
-- Name: recents fk_rails_5244e2cc55; Type: FK CONSTRAINT; Schema: public; Owner: -
-- Name: recents_old fk_rails_5244e2cc55; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.recents
ALTER TABLE ONLY public.recents_old
ADD CONSTRAINT fk_rails_5244e2cc55 FOREIGN KEY (subject_id) REFERENCES public.subjects(id);


Expand Down Expand Up @@ -4235,13 +4303,30 @@ ALTER TABLE ONLY public.users
ADD CONSTRAINT fk_rails_fedc809cf8 FOREIGN KEY (project_id) REFERENCES public.projects(id) ON UPDATE CASCADE ON DELETE RESTRICT;


--
-- Name: recents fk_recents_classifications; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.recents
ADD CONSTRAINT fk_recents_classifications FOREIGN KEY (classification_id) REFERENCES public.classifications(id);


--
-- Name: recents fk_recents_subjects; Type: FK CONSTRAINT; Schema: public; Owner: -
--

ALTER TABLE ONLY public.recents
ADD CONSTRAINT fk_recents_subjects FOREIGN KEY (subject_id) REFERENCES public.subjects(id);


--
-- PostgreSQL database dump complete
--

SET search_path TO "$user", public;

INSERT INTO "schema_migrations" (version) VALUES
('20260428222525'),
('20260407184533'),
('20260323120200'),
('20260323120100'),
Expand Down
Loading
Loading