Skip to content

[ENG-10737] Registrations are failing to auto-approve [privacy]#11718

Open
antkryt wants to merge 2 commits into
CenterForOpenScience:feature/pbs-26-9from
antkryt:fix/ENG-10737
Open

[ENG-10737] Registrations are failing to auto-approve [privacy]#11718
antkryt wants to merge 2 commits into
CenterForOpenScience:feature/pbs-26-9from
antkryt:fix/ENG-10737

Conversation

@antkryt
Copy link
Copy Markdown
Contributor

@antkryt antkryt commented Apr 28, 2026

Ticket

Purpose

fix check manual restart approval

Changes

  • schedule check_manual_restart_approval after force archive; remove it from archive_success
  • fix registration loading in the check_manual_restart_approval
  • use approve_past_pendings instead of process_manual_restart_approvals to approve a single registration
  • minor improvements
  • tests

Side Effects

QE Notes

CE Notes

Documentation

Copy link
Copy Markdown
Contributor

@mkovalua mkovalua left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Copy Markdown
Collaborator

@cslzchen cslzchen left a comment

Choose a reason for hiding this comment

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

First pass done, left a few questions / suggestions 🔥

@property
def archive_job(self):
return self.archive_jobs.first() if self.archive_jobs.count() else None
return self.archive_jobs.first()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nice clean-up, no need to check since .first() returns None if query set is empty.

Comment thread osf/models/sanctions.py Outdated
initiated_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.CASCADE)

@property
def auto_approve_at(self):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nitpicking: let's use auto_approval_time

Comment on lines +136 to +138
auto_approve_at = approval.auto_approve_at
if timezone.now() < auto_approve_at:
remaining = auto_approve_at - timezone.now()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Remember to change the local var auto_approval_at to auto_approval_time too.

Note: CMIIW, we need to use this local var because @property is calculated every time.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

you're right

Comment on lines -12 to +15
try:
registration = Registration.objects.get(_id=registration_id)
except Registration.DoesNotExist:
registration = Registration.load(registration_id)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe a personal preference but I think

registration = Registration.objects.filter(_id=registration_id).first()

is better than calling the load().

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Field _id doesn't exist on Registration, we cannot query it. So, we should either filter by registration.id or load(registration._id) [or do something really weird: guid = Guid.objects.filter(_id=registration_id).first(); registration = guid.referent 😁]


approval = registration.registration_approval
if not approval:
logger.info(f"Registration {registration_id} has no registration approval object")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I love the logs. Please take a look at what log level is most appropriate for each.

e.g. we sometime don't want to flood the logs and use debug, sometimes we want to highlight possible concerns by using warn, and some may need to be elevated to sentry

Comment on lines +50 to +51
logger.error(f"Error processing manual restart approval for {registration_id}: {e}")
sentry.log_exception(e)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

👍 for the sentry logs, it might be easier for us to find / relate to the error message than different exceptions in sentry. Let's add the following:

sentry.log_message(f"Error processing manual restart approval for {registration_id}: {str(e)}")`

Comment on lines -31 to +45
call_command(
'process_manual_restart_approvals',
registration_id=registration_id,
dry_run=False,
hours_back=24,
verbosity=1
)
logger.info(f"Processing manual restart approval for registration {registration_id}")
approve_past_pendings([approval], dry_run=False)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Curious on why using approve_past_pendings() instead of process_manual_restart_approvals fixes the issue?

I see other places calling the command process_manual_restart_approvals, do they need to be updated, or they are unrelated to this ticket?

Copy link
Copy Markdown
Contributor Author

@antkryt antkryt Jun 5, 2026

Choose a reason for hiding this comment

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

process_manual_restart_approvals is just a weird wrapper for the approve_past_pendings function. It collects list of registrations to approve and runs approve_past_pendings for this list. But check_manual_restart_approval works with a single registration, that's why I call approve_past_pendings directly here

Comment thread website/archiver/tasks.py
Comment on lines -448 to -450
if was_manually_restarted(dst):
logger.info(f'Registration {dst._id} was manually restarted, scheduling approval check')
delayed_manual_restart_approval.delay(dst._id, delay_minutes=5)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I understand we need to add this to force_archive() but why do we have to remove it from archive_success().

Copy link
Copy Markdown
Contributor Author

@antkryt antkryt Jun 5, 2026

Choose a reason for hiding this comment

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

archive_success is never triggered after the manual restart. IMO, we don't need delayed_manual_restart_approval function that runs if registration was_manually_restarted(dst) in the arhive_success()

I think this place is the main reason why ENG-10737 ticket was created, we run approval check where it makes no sense, it just doesn't do anything here

Copy link
Copy Markdown
Contributor Author

@antkryt antkryt Jun 5, 2026

Choose a reason for hiding this comment

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

Oh, this also means that I don't need to check if was_manually_restarted(dst) in the force_archive function (manual restart = force archive). I'll remove it

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.

3 participants