Created
September 2, 2022 18:20
-
-
Save gibizer/4542086aaa994fe9cb734c9fa2bcb357 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import functools | |
import random | |
import time | |
import eventlet | |
from oslo_concurrency import lockutils | |
eventlet.monkey_patch() | |
LOCK = "my-lock" | |
WORKER_NAME = None | |
def synchronized(*args, **kwargs): | |
"""A decorator that fixes lockutils.synchronized decorator to use the | |
proper threading.current_thread in an eventlet env | |
""" | |
def wrapper(f): | |
from unittest import mock | |
# make this optional | |
import eventlet | |
# apply the broken lock decorator first | |
f = lockutils.synchronized(*args, **kwargs)(f) | |
# then wrap the result to fix the current_thread call before entering | |
# the synchronized function. | |
# NOTE(gibi): This does more than what we need as it will keep the | |
# current_thread replaced for the whole execution of the function | |
# not just the time window when the lock.acquire() queries the | |
# current_thread. This is wrong just more than what we strictly need. | |
@functools.wraps(f) | |
def fixer(*args, **kwargs): | |
# FIXME(gibi) only do this if we are running in an eventlet | |
with mock.patch( | |
"threading.current_thread", new=eventlet.getcurrent | |
): | |
return f(*args, **kwargs) | |
return fixer | |
return wrapper | |
#@lockutils.synchronized(name=LOCK, fair=True) | |
@synchronized(name=LOCK, fair=True) | |
def locked_f(name): | |
global WORKER_NAME | |
if WORKER_NAME: | |
raise ValueError(f"{name}: I'm overlapping with {WORKER_NAME}") | |
WORKER_NAME = name | |
time.sleep(random.randint(0, 10) / 100) | |
WORKER_NAME = None | |
def do_work(name): | |
print('starting worker', name) | |
while True: | |
locked_f(name) | |
time.sleep(random.randint(0, 10) / 100) | |
print('.', end='') | |
def test(): | |
for i in range(2): | |
# eventlet.spawn is OK | |
# eventlet.spawn(do_work, f"worker{i}") | |
# eventlet.spawn_n is NOT OK | |
# it is probably https://github.com/eventlet/eventlet/issues/731 | |
# fasteners 0.14.1 is the last version this works anything newer | |
# is affected | |
eventlet.spawn_n(do_work, f"worker{i}") | |
time.sleep(10) | |
if __name__ == '__main__': | |
test() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment