-
Notifications
You must be signed in to change notification settings - Fork 28
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
moderation: added lock mechanism. #101
moderation: added lock mechanism. #101
Conversation
7f02362
to
105a804
Compare
def execute_moderation_actions(user_id, action): | ||
@shared_task(ignore_result=True, acks_late=True, retry=True) | ||
@lock_if_renew( | ||
lock_prefix="user_moderation_lock", |
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.
See my comment about this in the invenio-cache
PR
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.
After further discussions also with @zzacharo @jrcastro2, we propose to make everything a bit less sophisticated. The drawbacks I see here (and the PR in invenio-cache
) are:
- the decorator becomes quite complex because of the params parsing
- the
lock_if_renew
feels very tight to the usage in this specific context, not very easy to re-use - the lock is acquired even if the service will trigger a permission denied (and released). We might want to call the lock
acquire
after the permission check, so that we also have the user param:
def ...
...
user = UserAggregate.get_record(id_)
if user is None:
raise PermissionDeniedError()
Mutex(id).acquire() # `acquire_or_fail` or something
If you want to keep the decorator, here the proposal:
- the 2 decorators should be defined here, and they are used only in their specific context.
lock_user_moderation
should assert theid_
as second param, and use it. Similar for the celery task decorator. Such decorators should be used only here, cannot be re-used anywhere else. The only responsibility of the decorator is to calculate the cache key:
...
def decorate(*args, **kwargs):
user_id = args[1]
cache_key = f"user_moderation_lock.{user_id}"
...
I would not make configurable the prefix, I would remove USERS_RESOURCES_MODERATION_LOCK_KEY_PREFIX
.
- the decorator
lock_if_renew
is alsoreleasing
the lock at the end. It should be defined here, and used only here. Given that it is a decorator of a celery task, is it executed when calling it, or when the task starts? If the latter, it might be better to add it as first statement of the task, instead of a decorator, and take advantage of the mutex context manager:
with Mutex(id).acquire_or_renew():
...
# this will call release at the end
WDYT?
See also comments in the other PR. Let me know what you think, happy to chat IRL.
I agree that these decorators added a HUGE overhead, it was not worth it. I ended up dropping them and just having a wrapper of Example: def block(identity, id_):
...
self.require_permission(identity, "manage", record=user)
# Throws ``LockAcquireFailed`` if not acquired
ModerationMutex(id_).acquire()
... |
e40aef0
to
606a07d
Compare
606a07d
to
dddaf7c
Compare
closes #102
NEEDS:
Tests are failing since it needs the PR linked above.
Locally tests are passing: