From 93532fc3c75a159b7ce8909fe34d0957c58721a1 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Fri, 19 Dec 2025 03:00:43 +0100 Subject: [PATCH] Fix: only load jemalloc for main python process --- Dockerfile | 9 ++++++++- Dockerfile.base | 10 ---------- music_assistant/helpers/process.py | 17 +++++++++++++++-- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/Dockerfile b/Dockerfile index d956bd00..913c5083 100644 --- a/Dockerfile +++ b/Dockerfile @@ -82,4 +82,11 @@ EXPOSE 8095 WORKDIR $VIRTUAL_ENV -ENTRYPOINT ["mass", "--data-dir", "/data", "--cache-dir", "/data/.cache"] +# Entrypoint script that enables jemalloc for the main process only +RUN printf '#!/bin/sh\n\ +for path in /usr/lib/*/libjemalloc.so.2; do\n\ + [ -f "$path" ] && export LD_PRELOAD="$path" && break\n\ +done\n\ +exec mass "$@"\n' > /usr/local/bin/entrypoint.sh && chmod +x /usr/local/bin/entrypoint.sh + +ENTRYPOINT ["/usr/local/bin/entrypoint.sh", "--data-dir", "/data", "--cache-dir", "/data/.cache"] diff --git a/Dockerfile.base b/Dockerfile.base index 5be0e1d7..984767da 100644 --- a/Dockerfile.base +++ b/Dockerfile.base @@ -229,16 +229,6 @@ RUN ldconfig && ffmpeg -version && ffprobe -version RUN mkdir -p /usr/local/bin/widevine_cdm COPY widevine_cdm/* /usr/local/bin/widevine_cdm/ -# JEMalloc for more efficient memory management -# Dynamically set the correct path based on architecture -ARG TARGETARCH -RUN set -x \ - && if [ "$TARGETARCH" = "arm64" ]; then \ - echo "/usr/lib/aarch64-linux-gnu/libjemalloc.so.2" > /etc/ld.so.preload; \ - else \ - echo "/usr/lib/x86_64-linux-gnu/libjemalloc.so.2" > /etc/ld.so.preload; \ - fi - # we need to set (very permissive) permissions to the workdir # and /tmp to allow running the container as non-root RUN chmod -R 777 /tmp diff --git a/music_assistant/helpers/process.py b/music_assistant/helpers/process.py index c761ad31..0fa6183b 100644 --- a/music_assistant/helpers/process.py +++ b/music_assistant/helpers/process.py @@ -26,6 +26,15 @@ LOGGER = logging.getLogger(f"{MASS_LOGGER_NAME}.helpers.process") DEFAULT_CHUNKSIZE = 64000 +def get_subprocess_env(env: dict[str, str] | None = None) -> dict[str, str]: + """Get environment for subprocess, stripping LD_PRELOAD to avoid jemalloc warnings.""" + result = dict(os.environ) + result.pop("LD_PRELOAD", None) + if env: + result.update(env) + return result + + class AsyncProcess: """ AsyncProcess. @@ -65,7 +74,7 @@ class AsyncProcess: self._stdin = None if stdin is False else stdin self._stdout = None if stdout is False else stdout self._stderr = asyncio.subprocess.DEVNULL if stderr is False else stderr - self._env = env + self._env = get_subprocess_env(env) self._stderr_lock = asyncio.Lock() self._stdout_lock = asyncio.Lock() self._stdin_lock = asyncio.Lock() @@ -319,7 +328,10 @@ class AsyncProcess: async def check_output(*args: str, env: dict[str, str] | None = None) -> tuple[int, bytes]: """Run subprocess and return returncode and output.""" proc = await asyncio.create_subprocess_exec( - *args, stderr=asyncio.subprocess.STDOUT, stdout=asyncio.subprocess.PIPE, env=env + *args, + stderr=asyncio.subprocess.STDOUT, + stdout=asyncio.subprocess.PIPE, + env=get_subprocess_env(env), ) stdout, _ = await proc.communicate() assert proc.returncode is not None # for type checking @@ -336,6 +348,7 @@ async def communicate( stderr=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE, stdin=asyncio.subprocess.PIPE if input is not None else None, + env=get_subprocess_env(), ) stdout, stderr = await proc.communicate(input) assert proc.returncode is not None # for type checking -- 2.34.1