-
Notifications
You must be signed in to change notification settings - Fork 78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Soft-Delete for Students in Classes to Improve Performance #7588
base: master
Are you sure you want to change the base?
Implement Soft-Delete for Students in Classes to Improve Performance #7588
Conversation
16d69dc
to
116376f
Compare
eaa0dae
to
99f1231
Compare
5234c89
to
99f1231
Compare
db/migrate/20241014031828_add_deleted_at_to_course_reference_timelines.rb
Outdated
Show resolved
Hide resolved
db/migrate/20241014031810_add_deleted_at_to_course_achievements.rb
Outdated
Show resolved
Hide resolved
a7f602a
to
4ab1cad
Compare
cf811d9
to
65d2f44
Compare
1634ca3
to
ddc8aeb
Compare
3010168
to
6bdaff3
Compare
@@ -0,0 +1,48 @@ | |||
class ApplySoftDeleteForCourseUserAndAssociatedModels1 < ActiveRecord::Migration[7.2] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NameError: uninitialized constant ApplySoftDeleteForCourseUserAndAssociatedModels (NameError)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You get this error when run "rails db:migrate" right ?
@@ -111,9 +111,9 @@ | |||
context 'when the user is a Course Manager' do | |||
let(:user) { create(:course_manager, course: course).user } | |||
|
|||
it 'destroys the course' do | |||
it 'soft deletes the course' do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need course soft-deletion in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because we apply the soft-delete for CourseUser, which depend on Course.
We also allow to delete the Course, but if the Course is deleted, the CourseUser will need hard-delete to avoid "FK" violation.
So we need soft-delete for Course also.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can hard-delete CourseUser if associated Course is deleted.
However, if we want to implement soft-delete for Course, we should also ensure that the soft-deletion is performant + there must be a way to restore the course. We can do this in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The soft-delete for Course PR might need come first this PR, otherwise, a few of tests (which delete the Course) will be failed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can hard-delete CourseUser if associated Course is deleted.
db/migrate/20241021110207_apply_soft_delete_for_course_user_and_associated_models.rb
Outdated
Show resolved
Hide resolved
app/models/course_user.rb
Outdated
@@ -23,6 +24,15 @@ class CourseUser < ApplicationRecord | |||
# A set of roles which comprise the managers of a course. | |||
MANAGER_ROLES = Set[:manager, :owner].map { |v| roles[v] }.freeze | |||
|
|||
ASSOCIATED_MODELS = %i[ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these associated models exhaustive? How about course_discussion_posts, submissions, video_submissions, activities, etc?
Are we sure we want to cascade delete / soft-delete the associated models in the first place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please confirm if you have also checked the effects on jobs or not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have updated to skip cascading soft-delete on associated models, so we don't need to worry about side effects from this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This variable ASSOCIATED_MODELS
is unused, it should not exist.
app/models/course_user.rb
Outdated
@@ -176,6 +186,22 @@ def self.user?(user) | |||
all.exists?(user: user) | |||
end | |||
|
|||
# Soft delete the course user. | |||
def destroy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Soft-delete of course-user with a lot of activities still take >5 minutes. Your PR does not resolve the root issue. Please revise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only way is verify by similar data volumn on production. We can keep monitoring it on staging to see.
In theory, the soft-delete won't effect to the index and fk-constrains, so it would be much faster than hard-delete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I already verified the slow deletion using production-grade data, the problem is that there are many individual associated updates deletes involved.
I suggest we simply do soft-delete on course-user and do not touch associated models.
Subsequent calls to query data should ensure scope of course-user does not include soft-deleted course-user. discard
gem might be better for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spend time researching about discard. Might apply it later then.
@@ -14,6 +14,9 @@ gem 'tzinfo-data', platforms: [:mswin, :mswin64] | |||
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' | |||
gem 'rails', '~> 7.2.1' | |||
|
|||
# Soft delete | |||
gem 'paranoia' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The paranoia
gem github page also recommended to look at discard
gem
paranoia has some surprising behaviour (like overriding ActiveRecord's delete and destroy) and is not recommended for new projects. See discard's README for more details.
Have you taken a look at discard
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Learning the discard.
6fbf860
to
3b490c8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You still need to squash your commits before asking for review please.
More importantly, your PR does not resolve performance issue.
app/models/course_user.rb
Outdated
@@ -23,6 +24,15 @@ class CourseUser < ApplicationRecord | |||
# A set of roles which comprise the managers of a course. | |||
MANAGER_ROLES = Set[:manager, :owner].map { |v| roles[v] }.freeze | |||
|
|||
ASSOCIATED_MODELS = %i[ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This variable ASSOCIATED_MODELS
is unused, it should not exist.
name = value[:name].presence || value[:email] | ||
phantom = ActiveRecord::Type::Boolean.new.cast(value[:phantom]) | ||
{ name: name, | ||
email: value[:email], | ||
role: value[:role], | ||
phantom: phantom, | ||
timeline_algorithm: value[:timeline_algorithm] } | ||
end | ||
end.compact |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is there this change here?
change_table :course_achievements do |t| | ||
t.datetime :deleted_at, default: nil unless column_exists?(:course_achievements, :deleted_at) | ||
t.index :deleted_at unless index_exists?(:course_achievements, :deleted_at) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is there still deleted_at
on course_achievements
here?
@@ -111,9 +111,9 @@ | |||
context 'when the user is a Course Manager' do | |||
let(:user) { create(:course_manager, course: course).user } | |||
|
|||
it 'destroys the course' do | |||
it 'soft deletes the course' do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can hard-delete CourseUser if associated Course is deleted.
3b490c8
to
3f91dd2
Compare
To avoid long waiting from user when deleting student from class, need apply soft delete
To enhance user experience and minimize wait times when removing a student from the class, implementing a soft delete feature is crucial.