From 5a8d14eb4d9c563378f9bb4f7a3186d808c030bd Mon Sep 17 00:00:00 2001 From: sickprodigy Date: Sat, 15 Nov 2025 10:03:15 -0500 Subject: [PATCH] fix: Enable debug logging in send_discord_message for better memory tracking --- Scripts/discord_webhook.py | 101 ++++++++++++++++--------------------- main.py | 2 +- 2 files changed, 45 insertions(+), 58 deletions(-) diff --git a/Scripts/discord_webhook.py b/Scripts/discord_webhook.py index 53f8eea..49dc926 100644 --- a/Scripts/discord_webhook.py +++ b/Scripts/discord_webhook.py @@ -30,12 +30,14 @@ def _escape_json_str(s: str) -> str: def send_discord_message(message, username="Auto Garden Bot", is_alert=False, debug: bool = False): """ Send Discord message with aggressive GC and low-memory guard to avoid ENOMEM. + When debug=True prints mem_free at important steps so you can see peak usage. Returns True on success, False otherwise. """ global _NEXT_ALLOWED_SEND_TS resp = None url = _get_webhook_url(is_alert=is_alert) if not url: + if debug: print("DBG: no webhook URL configured") return False # Respect cooldown if we recently saw ENOMEM @@ -43,94 +45,82 @@ def send_discord_message(message, username="Auto Garden Bot", is_alert=False, de import time # type: ignore now = time.time() if _NEXT_ALLOWED_SEND_TS and now < _NEXT_ALLOWED_SEND_TS: + if debug: print("DBG: backing off until", _NEXT_ALLOWED_SEND_TS) return False except: pass try: - # 1) Free heap before TLS + # Lightweight local imports and GC import gc # type: ignore - gc.collect() - gc.collect() # run twice as a precaution + import time # type: ignore + + gc.collect(); gc.collect() if debug: - try: - print("DBG: mem after gc:", gc.mem_free() // 1024, "KB") - except: - pass + try: print("DBG: mem after gc:", gc.mem_free() // 1024, "KB") + except: pass - # 1b) quick mem check - avoid importing urequests/TLS when too low - try: - mem = getattr(gc, "mem_free", lambda: None)() - if debug: - try: - print("DBG: mem before import check:", (mem or 0) // 1024, "KB") - except: - pass - # lower threshold to match this board's free heap (~100 KB observed) - if mem is not None and mem < 90000: - if debug: print("DBG: skipping send (mem low)") - return False - except: - pass + # Quick mem check before importing urequests/SSL + mem = getattr(gc, "mem_free", lambda: None)() + if debug: + try: print("DBG: mem before import check:", (mem or 0) // 1024, "KB") + except: pass + # Conservative threshold — adjust as needed + if mem is not None and mem < 90000: + if debug: print("DBG: skip send (low mem)") + return False + + # Import urequests only when we plan to send try: - # 2) Import urequests locally (keeps RAM free when idle) + if debug: print("DBG: importing urequests...") import urequests as requests # type: ignore - # import here to measure allocation impact - if debug: - print("DBG: importing urequests...") except Exception as e: - # import likely failed due to ENOMEM or missing module; back off - # do not spam full exception text to conserve heap and serial output + # Back off when import fails (likely low-memory) try: - import time # type: ignore _NEXT_ALLOWED_SEND_TS = time.time() + 60 except: pass + if debug: print("DBG: urequests import failed:", e) print("Discord webhook import failed (backing off)") return False - gc.collect() # collect again after import to reduce fragmentation + gc.collect() if debug: - try: - print("DBG: mem after import:", gc.mem_free() // 1024, "KB") - except: - pass + try: print("DBG: mem after import:", gc.mem_free() // 1024, "KB") + except: pass - # 3) Keep payload tiny + # Build tiny payload url = str(url).strip().strip('\'"') - content = _escape_json_str(str(message)[:140]) # trim further + content = _escape_json_str(str(message)[:140]) user = _escape_json_str(str(username)[:32]) body_bytes = ('{"content":"%s","username":"%s"}' % (content, user)).encode("utf-8") - - # Minimal headers to reduce allocations headers = {"Content-Type": "application/json"} - # 4) Send if debug: - try: - print("DBG: mem before post:", gc.mem_free() // 1024, "KB") - except: - pass + try: print("DBG: mem before post:", gc.mem_free() // 1024, "KB") + except: pass + resp = requests.post(url, data=body_bytes, headers=headers) + if debug: - try: - print("DBG: mem after post:", gc.mem_free() // 1024, "KB", "status:", getattr(resp, "status", None)) - except: - pass + try: print("DBG: mem after post:", gc.mem_free() // 1024, "KB", "status:", getattr(resp, "status", None)) + except: pass status = getattr(resp, "status", getattr(resp, "status_code", None)) return bool(status and 200 <= status < 300) except Exception as e: - # On ENOMEM/MemoryError, back off for longer to avoid repeated failures + # On ENOMEM/MemoryError back off try: if ("ENOMEM" in str(e)) or isinstance(e, MemoryError): import time # type: ignore _NEXT_ALLOWED_SEND_TS = time.time() + 60 except: pass - # print concise message only + if debug: + try: print("DBG: exception in send:", e) + except: pass print("Discord webhook exception (backing off)") return False @@ -140,18 +130,15 @@ def send_discord_message(message, username="Auto Garden Bot", is_alert=False, de resp.close() except: pass - # Free refs and force GC try: - # only delete names if they exist - if 'resp' in locals(): - del resp - if 'body_bytes' in locals(): - del body_bytes - if 'requests' in locals(): - del requests + # remove large refs and force GC + if 'resp' in locals(): del resp + if 'body_bytes' in locals(): del body_bytes + if 'requests' in locals(): del requests except: pass try: - gc.collect() + import gc as _gc # type: ignore + _gc.collect() except: pass \ No newline at end of file diff --git a/main.py b/main.py index 224b231..37b2153 100644 --- a/main.py +++ b/main.py @@ -411,7 +411,7 @@ while True: mem_ok = getattr(_gc, 'mem_free', lambda: 0)() > 90000 if mem_ok: try: - ok = discord_webhook.send_discord_message(pending_discord_message) + ok = discord_webhook.send_discord_message(pending_discord_message, debug=True) if ok: print("Discord startup notification sent") discord_sent = True