[ENG-9044] Add manage command to resync preprint dois v1 - #11617
[ENG-9044] Add manage command to resync preprint dois v1#11617Vlad0n20 wants to merge 9 commits into
Conversation
cslzchen
left a comment
There was a problem hiding this comment.
Looks good overall. In addition to my questions/comments:
- Can we add logs of the output of the logs for you local run?
- We should also work with CE to test this command with a copy of production DB.
There was a problem hiding this comment.
Looks good 👍
- Make sure we test this against a copy of prod DB before running this on prod.
- If there are errors, need look further on why they fail, and probably another fix.
- Test if the default batch size is good, how long does it take, and also see how many times we need to repeat this.
- Make sure whoever uses this command knows that we need to repeatedly run this command.
| help=( | ||
| 'Maximum number of preprints to process per run (default: 500). ' | ||
| 'The command processes the first N eligible preprints and exits; ' | ||
| 're-run the command to continue with the next batch.' | ||
| ), |
There was a problem hiding this comment.
Oh, I see. This is an OK alternative to the loop I suggested. Just need to make sure whoever runs this command is aware of the fact that they need to keep running this command until none exists. Cc @adlius for your input on this.
e803a0c to
e1d4931
Compare
|
LGTM |
|
|
||
| user.date_last_logged_in = timezone.now() | ||
| user.external_identity[provider][provider_id] = 'VERIFIED' | ||
| if provider.lower() in OSFUser.SOCIAL_FIELDS: |
There was a problem hiding this comment.
Is this part of this ticket?
adlius
left a comment
There was a problem hiding this comment.
So I have a couple of suggestions. Since Crossref has a limit of 10000 submissions from a single user, might as well set the default batch size to 1000 and no rate limit. Instead let's run the task every five minutes so that we can send about 12000 requests per hour.
Also there are some commits from other branches that is in this PR.
| assert len(user.system_tags) == 1 | ||
|
|
||
| tag = Tag.all_tags.get(name=tag_name, system=True) | ||
| tag = Tag.all_tags.get(name=tag_name.lower(), system=True) |
There was a problem hiding this comment.
Same here. Is this part of this ticket?
| return qs | ||
|
|
||
|
|
||
| def resync_preprint_dois_v1(dry_run=True, batch_size=500, rate_limit=100, provider_id=None): |
There was a problem hiding this comment.
The rate limit of 100 is perhaps to restrictive. According to conversations with Crossref, they have a limit of 10000 pending items for each user.
There was a problem hiding this comment.
A 500 batch size is also perhaps too small.
|
|
||
| if rate_limit and not record_number % rate_limit: | ||
| logger.info(f'Rate limit reached at {record_number} preprints, sleeping {RATE_LIMIT_SLEEP}s') | ||
| time.sleep(RATE_LIMIT_SLEEP) |
There was a problem hiding this comment.
I am afraid this would clog the celery worker when this is run as a celery beat task.
brianjgeiger
left a comment
There was a problem hiding this comment.
Drive by:
- What queue are the tasks going onto? The default queue? We should probably ensure that they go on the Low Priority queue to keep from clogging the pipes too much.
- If we have a cron job that happens every five minutes, how are you going to run this in a
dry-runscenario to make sure it's going to work before the cron job runs? We might want to rethink our strategy here.
adlius
left a comment
There was a problem hiding this comment.
Some issues found during local testing.
adlius
left a comment
There was a problem hiding this comment.
Some more issues to fix.
| def create_identifier(self, preprint, category, include_relation=True): | ||
| if category == 'doi': | ||
| metadata = self.build_metadata(preprint, include_relation) | ||
| metadata = self.build_metadata(preprint, include_relation, include_unversioned_doi=True) |
There was a problem hiding this comment.
One more issue found during local testing: on an unmoderated preprint provider, when a user creates a new version but never publish that version, build_unversioned_posted_content would read preprint.get_guid().referent, which hands back that unpublished draft instead of the preprint actually being deposited. This is problematic because the unpublished draft will have date_published to be None and that would fail when building the payload.
| @@ -48,6 +49,23 @@ def post(self, request): | |||
| if record.get('status').lower() == 'success' and doi: | |||
| msg = record.find('msg').text | |||
| created = bool(msg == 'Successfully added') | |||
There was a problem hiding this comment.
So a DOI in the doi_unversioned category is only written when Crossref replies Successfully added. This could be a potential issue because if the DOI
is already registered, the email probably comes back with something like Successfully updated, so for those preprints
this branch never runs.
This would affect legacy preprints that exists before versioning was a thing. Their base guid is their original guid, so the DOI deposit here is the one registered years ago.
I checked against a local copy of prod db. One of preprint 22hq2 has 10.31219/osf.io/22hq2 already registered with crossref. So it's possible that the crossref response email wouldn't contain Successfully added but Successfully updated or some other language. Will need to confirm if that is indeed the case.
If that is the case, one possible fix is that for an unversioned DOI, store doi_unversioned on any successful record rather than only on Successfully added.
There was a problem hiding this comment.
There is another problem: if we run the resync task every five minutes, and if the preprint that was resynced in the last run still haven't received an email back confirming the update of the DOI, then in the next run it will be included in the resync task again. So we'd have to rethink how we should do this. One idea suggested by @cslzchen is that we follow the example in this PR and monitory the number of active tasks and spawn new tasks if the number of active task falls below a certain number (say 1000). In this case, we don't have to worry about running the task every five minutes.
| ).exclude( | ||
| tags__name='qatest', | ||
| tags__system=True, | ||
| ).select_related('provider').distinct() |
There was a problem hiding this comment.
we probably need an order_by here otherwise the ordering of the queryset would be undeterministic.
Ticket
Purpose
Changes
Side Effects
QE Notes
CE Notes
Documentation