Skip to content
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

Lock clients. Only one calls the Watchdog. #21

Merged
merged 19 commits into from
Jul 12, 2018
Merged

Lock clients. Only one calls the Watchdog. #21

merged 19 commits into from
Jul 12, 2018

Conversation

alanjds
Copy link
Owner

@alanjds alanjds commented Jul 10, 2018

Only one client can call the Watchdog. There is a Client lock to be held. Then it will check for the Watchdog lock. If not held, will invoke a Watchdog.

@alanjds alanjds requested a review from sbneto July 10, 2018 22:53
Copy link
Collaborator

@sbneto sbneto left a comment

Choose a reason for hiding this comment

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

  • Merge/generalize _get_client_lock and _get_watchdog_lock
  • Consider letting the remote lock expire by itself when set by the client and we can assure a watchdog was invoked
  • Minor stuff

lock_name = os.environ.get('CELERY_SERVERLESS_LOCK_NAME', 'celery_serverless:watchdog')
lock_url = os.environ.get('CELERY_SERVERLESS_LOCK_URL')
assert lock_url, 'The CELERY_SERVERLESS_LOCK_URL envvar should be set. Even to "disabled" to disable it.'

queue_url = os.environ.get('CELERY_SERVERLESS_QUEUE_URL')
assert queue_url, 'The CELERY_SERVERLESS_QUEUE_URL envvar should be set. Even to "disabled" to disable it.'
Copy link
Collaborator

@sbneto sbneto Jul 11, 2018

Choose a reason for hiding this comment

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

Letting it break with queue_url = os.environ['CELERY_SERVERLESS_QUEUE_URL'] and raising KeyError might make the code a bit simpler.

Copy link
Owner Author

@alanjds alanjds Jul 11, 2018

Choose a reason for hiding this comment

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

But then it gives less clue about how to solve the problem. "Is it a code error or my mistake?".

To change the message of a KeyError it will get as long as it is now. Is the change worth?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I would be ok without a specific message. Seeing os.environ['CELERY_SERVERLESS_QUEUE_URL'] on the error is enough for me to know that I am missing that envvar. But whether to change or not is up to you.

Copy link
Owner Author

Choose a reason for hiding this comment

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

For one line instead of two, I do prefer to put my own error message on this case.

return invoke_watchdog(with_lock=True, *args, **kwargs)
finally:
logger.debug('Releasing the client lock')
client_lock.release()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since a invoke_watchdog() was just made, we could let the client_lock expire by itself as long as it expires before the lifespan of a watchdog. This could avoid an eventual call by another client. Only works for distributed locks that expire though.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Yes. One though is to put a timeout instead of unlock the client_lock if the watchdog got invoked with success.

But right now the client lock can be a multiprocessing.Lock if Redis is not available on the client, or is undesirable to flood Redis with lock checks.

What do you think? Do this now or let go for some other PR?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it is ok as it is for now, lets just keep it in mind for future work.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Issue created for future work: #22

else:
assert lock_url, 'The CELERY_SERVERLESS_LOCK_URL envvar should be set. Even to "disabled" to disable it.'

if default and not lock_url:
Copy link
Collaborator

Choose a reason for hiding this comment

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

default_lock? Maybe this variable should always be a string and you could check for multiprocessing, since the redis version is a remote url.

Copy link
Owner Author

Choose a reason for hiding this comment

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

This born as a copy from _get_watchdog_lock.

Generalizing both will make the default more reasonable...

However, I had not understood your "be a string and check for multiprocessing". You mean receiving lock_url='multiprocessing'?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yep, I think it is strange that sometimes it is a class, sometimes a url.

Copy link
Owner Author

Choose a reason for hiding this comment

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

@sbneto Take a look on how _get_lock is now 👍

@@ -23,6 +24,25 @@
DEFAULT_STARTED_TIMEOUT = 30 # half minute


def _get_watchdog_lock(lock_url='', lock_name='', default=dummy_threading.Lock, enforce=True) -> '(Lock, str)':
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since _get_watchdog_lock and _get_client_lock should both work with redis locks, shouldn't their code be shared? It seems to me that there is a reasonable amount of copy/paste between both functions.

Copy link
Owner Author

@alanjds alanjds Jul 11, 2018

Choose a reason for hiding this comment

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

Yes. Both functions should be merged.

This is the 1st test-passing code version anyway ;) Lets get it better before merge the PR.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice! 👍

Copy link
Owner Author

Choose a reason for hiding this comment

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

Done. Take a look on _get_lock plz

@alanjds alanjds merged commit 00f9272 into master Jul 12, 2018
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.

2 participants