-
Notifications
You must be signed in to change notification settings - Fork 396
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
fix: refactor api_new_meeting_registration. Fixes #7608 #7724
base: main
Are you sure you want to change the base?
Conversation
rpcross
commented
Jul 21, 2024
- change to use JSON payload
- handle multiple records in one request
- change to use JSON payload - handle multiple records in one request
I am working on tests for this. Using a JSON payload means the existing require_api_key decorator won't work. Assuming JSON payload is the way to go, are there other precedents for checking API key? Function can do it's own validation, or can update decorator. |
datatracker/ietf/api/ietf_utils.py Lines 27 to 46 in b5ab4b6
|
@rpcross This may have fallen into the cracks because of 120? |
@rpcross - lets discuss this soon? |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #7724 +/- ##
==========================================
- Coverage 88.95% 88.69% -0.27%
==========================================
Files 303 310 +7
Lines 41273 40951 -322
==========================================
- Hits 36713 36320 -393
- Misses 4560 4631 +71 ☔ View full report in Codecov by Sentry. |
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.
There are a few comments inline, but I have reservations about the strategy used for removing/updating/replacing MeetingRegistration
records. As it's done, I'm pretty sure there are race conditions that can lead to corrupt registrations. E.g., if two identical requests to register a user are at nearly the same time, two identical registrations may be created. This will happen if the later-running request handler executes line 334 (regs = MeetingRegistration.objects.filter(meeting__number=number, email=email)
) before the earlier-running handler executes line 357 (new_reg.save()
).
At minimum, we ought to put a uniqueness constraint on MeetingRegistration
to guard against this. Not sure, but I think it'd need to be over email
, meeting
, and reg_type
.
I think that constraint should be enough to avoid data corruption, but it would result in some API errors that were unnecessary. I.e., the two simultaneous identical requests would both "succeed" in that their work would be done as requested, but the later one would get back an error. It'd be very cool to rework the API using get_or_create
(plus probably some additional subtlety handling) to avoid this, but I'm not sure it's necessary.
# get person | ||
person = Person.objects.filter(email__address=email).first() | ||
if not person: | ||
log.log(f"api_new_meeting_registration_v2 no Person found for {email}") |
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.
Do you want the registration system to know that the registration it just sent doesn't match a person? Think about whether telling the person that just registered "Oh no - something went wrong with your registration" might move some of the person-fixup work we do at meetings to the period before the meeting.
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 left this in for completeness, but do we expect this to happen? Since Registration now requires the participant to be logged in via the Datatracker, the existence of Person should be largely assured. My feeling is that all auth issues at the last few meetings have been either 1) someone is trying to access meetecho without having registered, 2) duplicate person issues.
# get existing records if any | ||
regs = MeetingRegistration.objects.filter(meeting__number=number, email=email) | ||
pks = [r.pk for r in regs] | ||
|
||
for registration in payload: | ||
new_reg = MeetingRegistration( | ||
meeting=meeting, | ||
first_name=registration['first_name'], | ||
last_name=registration['last_name'], | ||
affiliation=registration['affiliation'], | ||
country_code=registration['country_code'], | ||
person=person, | ||
email=email, | ||
reg_type=registration['reg_type'], | ||
ticket_type=registration['ticket_type'], | ||
checkedin=registration['checkedin']) | ||
|
||
# update any existing records if there are any | ||
new_reg.pk = _safe_pop(pks) | ||
if new_reg.pk: | ||
log.log(f"Updating MeetingRegistration record for meeting:{meeting} email:{email}") | ||
else: | ||
log.log(f"New MeetingRegistration record for meeting:{meeting} email:{email}") | ||
new_reg.save() |
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 confuses me, and looks error-prone - it could effectively swap pks on records depending on the order L334 returns objects. Why isn't this using get_or_create with defaults and using the created flag instead?
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.
Is there a reason to prefer the current model where a single person's registration is represented as several MeetingRegistration
instances? The gymnastics in checking that the payload pertains only to a single email seems to be begging for a model that represents that as a single registration per email with fields representing the different options.
I think that'll greatly simplify the API implementation. It'll mean a migration, but I don't think that'll be terribly difficult.
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.
Also, as far as I can tell there are currently no models with foreign keys into MeetingRegistration
so it's not an going to break things now if PKs get swapped, but it'll do something in between cramping our style and causing serious bugs later.
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 confuses me, and looks error-prone - it could effectively swap pks on records depending on the order L334 returns objects. Why isn't this using get_or_create with defaults and using the created flag instead?
It certainly could swap pks. It is a brute force approach I chose for it's definitiveness. We can’t use get_or_create because there may be more than one existing registration record even for the same reg_type (two onsite one-day regs for example) AND the reg_type can change, switch from onsite to remote, so we’d be updating a record with a different reg_type. The simplest approach is to delete and re-create, or fully overwrite as I have done. Other approaches require more complexity. The following might work. Assuming that any notification will include all existing registrations for a given participant, and that a single registration save triggers the notification than it should be true that only one registration is added or was changed. If payload == 1 we can use get_or_create. (Except if payload == 1 and 2 already exist it means we missed a cancel somewhere). If payload > 1 we know that only one is new or updated and the rest should match existing records. We can do the work to determine which record doesn't match existing. This is a more complex procedure but would result in preserving the record PKs.
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.
Is there a reason to prefer the current model where a single person's registration is represented as several
MeetingRegistration
instances? The gymnastics in checking that the payload pertains only to a single email seems to be begging for a model that represents that as a single registration per email with fields representing the different options.I think that'll greatly simplify the API implementation. It'll mean a migration, but I don't think that'll be terribly difficult.
We actually started with one MeetingRegistration record per person and had a reg_type field that was text and contained comma separated types, "onsite, hackathon_onsite", which proved problematic to deal with so we change the model to match registration, which could be multiple registration records per person. The current model seems appropriate.
<- meeting 120 onsite week pass
person A <- meeting 121 onsite one day pass
<- meeting 121 remote week pass
Or maybe breakout another table?
person A <- meeting 121 <- onsite one-day
<- remote week pass
# delete any remaining records | ||
if pks: | ||
MeetingRegistration.objects.filter(pk__in=pks).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.
If L333-L356 change, this will have to be adjusted to match
# handle nomcom volunteer | ||
if registration['is_nomcom_volunteer'] and person: | ||
try: | ||
nomcom = NomCom.objects.get(is_accepting_volunteers=True) |
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.
Does the registration system check to see if a nomcom is accepting volunteers before offering the choice to someone?
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.
It does not. It's another level of integration that could be added. My understanding was that AMS would coordinate with the nomcom chair. When prepping to open registration if nomcom is accepting volunteers I would ensure the volunteer question appears on the reg form.