-
Notifications
You must be signed in to change notification settings - Fork 7
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
Remote patron activity sync celery task (PP-1164) #1894
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1894 +/- ##
==========================================
+ Coverage 90.16% 90.28% +0.11%
==========================================
Files 325 332 +7
Lines 39701 39865 +164
Branches 8645 8647 +2
==========================================
+ Hits 35798 35991 +193
+ Misses 2597 2581 -16
+ Partials 1306 1293 -13 ☔ View full report in Codecov by Sentry. |
I'm doing some local testing on this, and getting the PR ready for our hosting environment, but I think while that is happening this is ready for a code review. |
0d61b94
to
3fd7c8b
Compare
3fd7c8b
to
c17e068
Compare
|
4317047
to
aa3d646
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.
This looks great! 🥇
A couple of comments, but nothing that would stop this going in as-is.
# We do this right now because we are using types-redis, which defines Redis as a generic type, | ||
# even though it is not actually generic. Redis 5 now support type hints natively, so we we | ||
# should be able to drop types-redis in the future. | ||
# Currently, the build in type hints are incomplete at best, so types-redis does a better job. |
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.
Minor typo: "build" -> "built"?
|
||
class RedisPrefixCheckMixin(ABC): | ||
""" | ||
A mixin that with functions to check that the keys used in a redis command have the expected |
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.
Minor: "that with" -> "with"?
def _check_prefix(self, *args: Any) -> None: | ||
arg_list = list(args) | ||
command = arg_list.pop(0) | ||
cmd_args = self._PREFIXED_COMMANDS.get(command) |
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 it possible for command
NOT to be all uppercase here?
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 might be, if someone called execute_command
directly. I'll call upper()
just in case.
@@ -256,6 +252,7 @@ def test_attempt_renew_with_local_loan_and_no_available_copies( | |||
# Contrast with the way NoAvailableCopies is handled in | |||
# test_loan_becomes_hold_if_no_available_copies. | |||
circulation_api.remote.queue_checkout(NoAvailableCopies()) | |||
circulation_api.remote.queue_checkout(NoAvailableCopies()) |
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 another checkout here? Might be good to add a comment about 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.
Good catch, we don't actually need a second checkout here. Must have been an accidental copy / paste on my part.
status = patron_activity_status.status() | ||
state = status.state.name if status is not None else "UNKNOWN" | ||
task.log.info( | ||
f"Patron activity sync not needed (state: {state}) for " |
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's not clear to me what "not needed" means here. I seems like it could mean a variety of things (a sync is already in progress, a sync failed recently, etc.).
Perhaps "A new patron activity sync will not be queued..." would be more clear. Or better yet, something that makes the underlying reason more clear.
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 this more clear?
f"Patron activity sync task could not acquire lock. Task will not "
f"perform sync. Lock state ({state}) for patron (id: {patron_id}) and "
f"collection (id: {collection_id})."
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.
Definitely more clear!
if cmd_args is not None: | ||
for key in cmd_args.key_args(arg_list): | ||
if not key.startswith(self._prefix): | ||
raise RedisValueError( | ||
f"Key {key} does not start with prefix {self._prefix}. Command {command} args: {arg_list}" | ||
) | ||
else: | ||
raise RedisValueError( | ||
f"Command {command} is not checked for prefix. Args: {arg_list}" | ||
) |
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.
Minor: Swapping the if
and else
blocks would let us guard and simplify here:
if cmd_args is None:
raise RedisValueError(
f"Command {command} is not checked for prefix. Args: {arg_list}"
)
for key in cmd_args.key_args(arg_list):
...
a83fc20
to
87caa2f
Compare
Description
This PR updates our Patron API that sync with remote providers to do the sync as an async celery task, rather then in the main web thread worker. To coordinate these patron activity sync tasks, I wired up redis as a service that we can use to store data, not just as a celery broker.
Redis is used to store the state of the patron activity sync and as a distributed lock, so that only one task is doing a sync at a time.
🚨 This needs a PR to update our deployments, since we have new environment variables. I'm going to leave it in draft until its ready to be merged.PR up for this.Motivation and Context
This should improve our speed and responsiveness when syncing the loans feed and will help with the issues we have been seeing in CA where a provider going down can cause the whole CM to become unresponsive because we are waiting for so long for the remote requests.
JIRA:
Both those tasks in JIRA ended up being worked on together in this one, since it wasn't easy to pull them apart.
How Has This Been Tested?
Checklist