Skip to content
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

Open
wants to merge 11 commits into
base: master
Choose a base branch
from

Conversation

phungmanhcuong
Copy link
Contributor

@phungmanhcuong phungmanhcuong commented Oct 9, 2024

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.

@phungmanhcuong phungmanhcuong self-assigned this Oct 9, 2024
@phungmanhcuong phungmanhcuong marked this pull request as draft October 9, 2024 02:01
@phungmanhcuong phungmanhcuong force-pushed the mcphung/soft-delete-for-removing-student-from-class branch 5 times, most recently from 16d69dc to 116376f Compare October 14, 2024 10:06
@phungmanhcuong phungmanhcuong marked this pull request as ready for review October 14, 2024 10:08
@phungmanhcuong phungmanhcuong force-pushed the mcphung/soft-delete-for-removing-student-from-class branch 2 times, most recently from eaa0dae to 99f1231 Compare October 15, 2024 05:26
@phungmanhcuong phungmanhcuong force-pushed the mcphung/soft-delete-for-removing-student-from-class branch from 5234c89 to 99f1231 Compare October 15, 2024 06:38
@cysjonathan cysjonathan removed the request for review from syoopie October 15, 2024 09:25
db/schema.rb Outdated Show resolved Hide resolved
app/models/course/group_user.rb Outdated Show resolved Hide resolved
spec/models/course_user_spec.rb Show resolved Hide resolved
@phungmanhcuong phungmanhcuong force-pushed the mcphung/soft-delete-for-removing-student-from-class branch from a7f602a to 4ab1cad Compare October 15, 2024 09:47
app/controllers/users_controller.rb Outdated Show resolved Hide resolved
app/controllers/users_controller.rb Outdated Show resolved Hide resolved
Gemfile Outdated Show resolved Hide resolved
@phungmanhcuong phungmanhcuong force-pushed the mcphung/soft-delete-for-removing-student-from-class branch 12 times, most recently from cf811d9 to 65d2f44 Compare October 21, 2024 05:43
@phungmanhcuong phungmanhcuong force-pushed the mcphung/soft-delete-for-removing-student-from-class branch 3 times, most recently from 1634ca3 to ddc8aeb Compare October 21, 2024 11:07
@phungmanhcuong phungmanhcuong changed the title refactor(soft-delete-student-class): soft-delete when removing studen… Implement Soft-Delete for Students in Classes to Improve Performance Oct 21, 2024
@phungmanhcuong phungmanhcuong force-pushed the mcphung/soft-delete-for-removing-student-from-class branch 2 times, most recently from 3010168 to 6bdaff3 Compare October 21, 2024 12:25
@@ -0,0 +1,48 @@
class ApplySoftDeleteForCourseUserAndAssociatedModels1 < ActiveRecord::Migration[7.2]
Copy link
Contributor

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)

Copy link
Contributor Author

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 ?

tests/tests/users/sign-up.spec.ts Outdated Show resolved Hide resolved
@@ -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
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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.

@@ -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[
Copy link
Contributor

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?

Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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.

@@ -176,6 +186,22 @@ def self.user?(user)
all.exists?(user: user)
end

# Soft delete the course user.
def destroy
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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'
Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Learning the discard.

app/models/course_user.rb Outdated Show resolved Hide resolved
@phungmanhcuong phungmanhcuong force-pushed the mcphung/soft-delete-for-removing-student-from-class branch 5 times, most recently from 6fbf860 to 3b490c8 Compare October 22, 2024 07:52
Copy link
Contributor

@cysjonathan cysjonathan left a 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.

@@ -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[
Copy link
Contributor

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
Copy link
Contributor

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?

Comment on lines +13 to +15
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)
Copy link
Contributor

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?

db/schema.rb Outdated Show resolved Hide resolved
@@ -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
Copy link
Contributor

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.

@phungmanhcuong phungmanhcuong force-pushed the mcphung/soft-delete-for-removing-student-from-class branch from 3b490c8 to 3f91dd2 Compare October 22, 2024 08:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants