Skip to content

Commit

Permalink
Use file existence for registry mutex (#959)
Browse files Browse the repository at this point in the history
Part of [Service provider auctions for web deployments](https://www.notion.so/Service-provider-auctions-for-web-deployments-104a6b22d47280dbad51d28aa3a91d75)

Reviewed-on: https://git.vdb.to/cerc-io/stack-orchestrator/pulls/959
Reviewed-by: ashwin <[email protected]>
Co-authored-by: Prathamesh Musale <[email protected]>
Co-committed-by: Prathamesh Musale <[email protected]>
  • Loading branch information
prathamesh0 authored and ashwin committed Oct 29, 2024
1 parent 5f8e809 commit f64ef5d
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 14 deletions.
72 changes: 59 additions & 13 deletions stack_orchestrator/deploy/webapp/registry_mutex.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,59 @@
import fcntl
from functools import wraps
import os
import time

# Define default file path for the lock
DEFAULT_LOCK_FILE_PATH = "/tmp/registry_mutex_lock_file"
LOCK_TIMEOUT = 30
LOCK_RETRY_INTERVAL = 3


def acquire_lock(client, lock_file_path, timeout):
# Lock alreay acquired by the current client
if client.mutex_lock_acquired:
return

while True:
try:
# Check if lock file exists and is potentially stale
if os.path.exists(lock_file_path):
with open(lock_file_path, 'r') as lock_file:
timestamp = float(lock_file.read().strip())

# If lock is stale, remove the lock file
if time.time() - timestamp > timeout:
print(f"Stale lock detected, removing lock file {lock_file_path}")
os.remove(lock_file_path)
else:
print(f"Lock file {lock_file_path} exists and is recent, waiting...")
time.sleep(LOCK_RETRY_INTERVAL)
continue

# Try to create a new lock file with the current timestamp
fd = os.open(lock_file_path, os.O_CREAT | os.O_EXCL | os.O_RDWR)
with os.fdopen(fd, 'w') as lock_file:
lock_file.write(str(time.time()))

client.mutex_lock_acquired = True
print(f"Registry lock acquired, {lock_file_path}")

# Lock successfully acquired
return

except FileExistsError:
print(f"Lock file {lock_file_path} exists, waiting...")
time.sleep(LOCK_RETRY_INTERVAL)


def release_lock(client, lock_file_path):
try:
os.remove(lock_file_path)

client.mutex_lock_acquired = False
print(f"Registry lock released, {lock_file_path}")
except FileNotFoundError:
# Lock file already removed
pass


def registry_mutex():
Expand All @@ -13,18 +64,13 @@ def wrapper(self, *args, **kwargs):
if self.mutex_lock_file:
lock_file_path = self.mutex_lock_file

with open(lock_file_path, 'w') as lock_file:
try:
# Try to acquire the lock
fcntl.flock(lock_file, fcntl.LOCK_EX)

# Call the actual function
result = func(self, *args, **kwargs)
finally:
# Always release the lock
fcntl.flock(lock_file, fcntl.LOCK_UN)

return result
# Acquire the lock before running the function
acquire_lock(self, lock_file_path, LOCK_TIMEOUT)
try:
return func(self, *args, **kwargs)
finally:
# Release the lock after the function completes
release_lock(self, lock_file_path)

return wrapper

Expand Down
4 changes: 3 additions & 1 deletion stack_orchestrator/deploy/webapp/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ class LaconicRegistryClient:
def __init__(self, config_file, log_file=None, mutex_lock_file=None):
self.config_file = config_file
self.log_file = log_file
self.mutex_lock_file = mutex_lock_file
self.cache = AttrDict(
{
"name_or_id": {},
Expand All @@ -126,6 +125,9 @@ def __init__(self, config_file, log_file=None, mutex_lock_file=None):
}
)

self.mutex_lock_file = mutex_lock_file
self.mutex_lock_acquired = False

def whoami(self, refresh=False):
if not refresh and "whoami" in self.cache:
return self.cache["whoami"]
Expand Down

0 comments on commit f64ef5d

Please sign in to comment.