mail: malloc_trim nach search_mail/read_attachment gegen RSS-Bloat
search_mail dekodiert bei breiten Queries den Body jeder Mail; CPython/glibc gibt den Peak-RSS nicht ans OS zurueck -> Prozess wuchs auf 6.2 GB und hat zusammen mit einem 2-TB-Restic-Lauf den Server-RAM/Swap gesprengt (restic OOM). Fix: gc.collect()+malloc_trim(0) nach den speicherintensiven Tools. Zusaetzlich systemd MemoryMax=2G/MemoryHigh=1.5G als Sicherheitsnetz (Drop-In, nicht im Repo). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,8 @@ import io
|
||||
import contextlib
|
||||
import imaplib
|
||||
import mailbox
|
||||
import gc
|
||||
import ctypes
|
||||
from email.header import decode_header
|
||||
from email.mime.text import MIMEText
|
||||
from email.utils import formatdate
|
||||
@@ -47,6 +49,22 @@ mcp = FastMCP("Mail", stateless_http=True,
|
||||
transport_security={"enable_dns_rebinding_protection": False})
|
||||
|
||||
|
||||
try:
|
||||
_libc = ctypes.CDLL("libc.so.6")
|
||||
except OSError:
|
||||
_libc = None
|
||||
|
||||
|
||||
def _trim_memory():
|
||||
"""gc + malloc_trim: Speicher nach grossen Operationen ans OS zurueckgeben."""
|
||||
gc.collect()
|
||||
if _libc is not None:
|
||||
try:
|
||||
_libc.malloc_trim(0)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _safe_decode(payload, charset):
|
||||
"""Decode bytes robust gegen unbekannte/kaputte Charsets (z.B. 'x-unknown')."""
|
||||
if not isinstance(payload, bytes):
|
||||
@@ -207,7 +225,9 @@ def search_mail(
|
||||
continue
|
||||
results.append(f"[{date_str}] {frm} -> {to}\n Subject: {subj}\n Account: {acct_name}, Folder: {fld}, Key: {key}")
|
||||
if len(results) >= limit:
|
||||
_trim_memory()
|
||||
return "\n\n".join(results)
|
||||
_trim_memory()
|
||||
return "\n\n".join(results) if results else "No results found"
|
||||
|
||||
|
||||
@@ -254,6 +274,7 @@ def read_attachment(
|
||||
attachment_index: Annotated[int, Field(description="Attachment number from the read_mail attachment list (1-based)")],
|
||||
) -> list[TextContent | ImageContent | EmbeddedResource]:
|
||||
"""Read an email attachment. Images shown inline, PDFs as extracted text, text directly, other documents as binary. Get the index from read_mail."""
|
||||
_trim_memory()
|
||||
user = get_current_user()
|
||||
if not user:
|
||||
return [TextContent(type="text", text="Error: not authenticated")]
|
||||
|
||||
Reference in New Issue
Block a user