Skip to content

UnleashClient.destroy() removes shared cache directory across processes #390

@crimoniv

Description

@crimoniv

Describe the bug
The default Unleash cache implementation (FileCache, based of fcache.cache.FileCache) uses platformdirs.user_cache_dir() to compute the cache directory. On Linux systems, this resolves to ${HOME}/.cache/APP_NAME/cache (where APP_NAME is defined via UnleashClient).

When UnleashClient.destroy() is executed (i.e., to ensure proper metrics flush before shutdown), the entire cache directory is removed as part of the cleanup process. As a result, every other running process using the same APP_NAME (and, therefore, relying on the same cache path) fails when attempting to use the cache.

To Reproduce
Steps to reproduce the behavior:

  1. Initialize UnleashClient and register client.destroy() in an atexit.register handler.
  2. Start a long running process (i.e., a FastAPI app).
  3. Open an interactive shell to the FastAPI app in a new process.
  4. Close the interactive shell. It will trigger UnleashClient.destroy() as part of the shutdown.
  5. PollingConnector._fetch_and_load() will start raising errors when writing to the long running process' cache.

Expected behavior
We would expect both the FastAPI process and the interactive shell to use its own, isolated cache dir, but the cache dir is currently shared between every process running with the same APP_NAME.

Logs

Traceback (most recent call last):
  File "shutil.py", line 856, in move
    os.rename(src, real_dst)
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/tmpjoiroou9' -> '/root/.cache/my-project-name/cache/2f636c69656e742f6665617475726573'

Traceback (most recent call last):
  File "apscheduler/executors/base.py", line 131, in run_job
    retval = job.func(*job.args, **job.kwargs)
  File "UnleashClient/connectors/polling_connector.py", line 72, in _fetch_and_load
    self.cache.set(FEATURES_URL, state)
  File "UnleashClient/cache.py", line 129, in set
    self._cache[key] = value
  File "fcache/cache.py", line 274, in __setitem__
    self._write_to_file(filename, value)
  File "fcache/cache.py", line 259, in _write_to_file
    rename(tmp, filename)
  File "shutil.py", line 876, in move
    copy_function(src, real_dst)
  File "shutil.py", line 468, in copy2
    copyfile(src, dst, follow_symlinks=follow_symlinks)
  File "shutil.py", line 262, in copyfile
    with open(dst, 'wb') as fdst:
FileNotFoundError: [Errno 2] No such file or directory: '/root/.cache/my-project-name/cache/2f636c69656e742f6665617475726573'

Additional context

  • Python: 3.13.7
  • UnleashClient: 6.5.1
  • System: Debian Trixie (python:3.13.7-slim-trixie)
  • Architecture: ARM64

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions