Skip to content

Commit ce28aff

Browse files
committed
Merge branch 'tickets/DM-49245'
2 parents d1f69d3 + 6589cd4 commit ce28aff

File tree

2 files changed

+53
-7
lines changed

2 files changed

+53
-7
lines changed

config/gunicorn.conf.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,13 @@
2222

2323
def when_ready(server):
2424
tracker = activator.repo_tracker.LocalRepoTracker.get()
25-
tracker.init_tracker()
25+
old_repos = tracker.init_tracker()
26+
for repo in old_repos:
27+
try:
28+
shutil.rmtree(repo)
29+
except FileNotFoundError:
30+
pass
31+
# Propagate all other exceptions; it means the repo is still around!
2632

2733

2834
def child_exit(server, worker):
@@ -37,4 +43,10 @@ def child_exit(server, worker):
3743

3844
def on_exit(server):
3945
tracker = activator.repo_tracker.LocalRepoTracker.get()
40-
tracker.cleanup_tracker()
46+
dangling_repos = tracker.cleanup_tracker()
47+
for repo in dangling_repos:
48+
try:
49+
shutil.rmtree(repo)
50+
except FileNotFoundError:
51+
pass
52+
# Propagate all other exceptions; it means the repo is still around!

python/activator/repo_tracker.py

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@
4343
_log.setLevel(logging.DEBUG)
4444

4545

46+
# Absolute path on this worker's system where local repos may be created
47+
local_repos = os.environ.get("LOCAL_REPOS", "/tmp")
48+
49+
4650
class LocalRepoTracker:
4751
"""A mapping of process IDs to repo locations.
4852
@@ -56,7 +60,10 @@ class LocalRepoTracker:
5660
"""
5761
_instance: typing.Self | None = None
5862

59-
_BACKEND_FILE = os.path.join(os.path.expanduser("~"), ".repo.tracker.csv")
63+
# Temp space is guaranteed to be in persistent storage (local disk
64+
# in unit tests, ephemeral in container). The same is NOT true for
65+
# ~ or /app.
66+
_BACKEND_FILE = os.path.join(local_repos, ".repo.tracker.csv")
6067

6168
@staticmethod
6269
def get() -> typing.Self:
@@ -71,19 +78,46 @@ def init_tracker(self):
7178
This method should be called by the parent process of any processes
7279
that will use the tracker, or at least a process that is guaranteed
7380
to outlast the client processes.
81+
82+
Return
83+
------
84+
old_repos : collection [`str`]
85+
The contents of any pre-existing registry.
7486
"""
75-
with self._open_exclusive(self._BACKEND_FILE, mode="x") as f:
76-
self._write_data(f, {})
77-
_log.info("Local repo tracker is ready for use.")
87+
try:
88+
with self._open_exclusive(self._BACKEND_FILE, mode="x") as f:
89+
self._write_data(f, {})
90+
return set()
91+
except FileExistsError:
92+
# Don't log a stack trace, because this is likely to be called from
93+
# a non-JSON logger.
94+
with self._open_exclusive(self._BACKEND_FILE, mode="r+") as f:
95+
data = self._read_data(f)
96+
self._write_data(f, {})
97+
_log.warning("Dangling repo registry found with the following repos: %s", data.values())
98+
return data.values()
99+
finally:
100+
_log.info("Local repo tracker is ready for use.")
78101

79102
def cleanup_tracker(self):
80103
"""Remove the tracker and delete all state.
104+
105+
Return
106+
------
107+
repos : collection [`str`]
108+
The (hopefully empty) set of repos that were still registered.
81109
"""
82110
try:
111+
with self._open_exclusive(self._BACKEND_FILE, mode="r") as f:
112+
data = self._read_data(f)
113+
repos = data.values()
83114
os.remove(self._BACKEND_FILE)
84115
except FileNotFoundError:
85-
pass
116+
repos = set()
86117
_log.info("Local repo tracker has been cleaned up.")
118+
if repos:
119+
_log.warning("The following repos were still registered: %s", repos)
120+
return repos
87121

88122
@staticmethod
89123
@contextlib.contextmanager

0 commit comments

Comments
 (0)