From 13e3a56fa683d29f92fd7af1dd2c9d25af3385f8 Mon Sep 17 00:00:00 2001 From: sickprodigy Date: Fri, 14 Nov 2025 21:48:19 -0500 Subject: [PATCH] fix: Add low-memory guard and cooldown for Discord message sending This isn't quite the fix though just want to save my position till tomorrow and see what changes come up before and after --- Scripts/discord_webhook.py | 29 +++++++++++++++++++++++++---- main.py | 1 + 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Scripts/discord_webhook.py b/Scripts/discord_webhook.py index fdf9307..58fb057 100644 --- a/Scripts/discord_webhook.py +++ b/Scripts/discord_webhook.py @@ -1,5 +1,7 @@ # Minimal module-level state (only what we need) _CONFIG = {"discord_webhook_url": None, "discord_alert_webhook_url": None} +# Cooldown after low-memory failures (epoch seconds) +_NEXT_ALLOWED_SEND_TS = 0 def set_config(cfg: dict): """Initialize module with minimal values from loaded config (call from main).""" @@ -30,29 +32,41 @@ def send_discord_message(message, username="Auto Garden Bot", is_alert=False): Send Discord message with aggressive GC and low-memory guard to avoid ENOMEM. Returns True on success, False otherwise. """ + global _NEXT_ALLOWED_SEND_TS resp = None url = _get_webhook_url(is_alert=is_alert) if not url: return False + # Respect cooldown if we recently saw ENOMEM + try: + import time # type: ignore + now = time.time() + if _NEXT_ALLOWED_SEND_TS and now < _NEXT_ALLOWED_SEND_TS: + return False + except: + pass + try: # 1) Free heap before TLS import gc # type: ignore gc.collect() try: # If MicroPython provides mem_free, skip send if heap is very low - if hasattr(gc, "mem_free") and gc.mem_free() < 60000: # ~60KB threshold + # TLS can be spiky and fragmented; be conservative. + if hasattr(gc, "mem_free") and gc.mem_free() < 100000: # ~100KB threshold return False except: pass # 2) Import urequests locally (keeps RAM free when idle) import urequests as requests # type: ignore + gc.collect() # collect again after import to reduce fragmentation # 3) Keep payload tiny url = str(url).strip().strip('\'"') - content = _escape_json_str(str(message)[:160]) - user = _escape_json_str(str(username)[:40]) + content = _escape_json_str(str(message)[:140]) # trim further + user = _escape_json_str(str(username)[:32]) body_bytes = ('{"content":"%s","username":"%s"}' % (content, user)).encode("utf-8") # Minimal headers to reduce allocations @@ -65,6 +79,13 @@ def send_discord_message(message, username="Auto Garden Bot", is_alert=False): return bool(status and 200 <= status < 300) except Exception as e: + # On ENOMEM/MemoryError, back off for 30 seconds to avoid repeated failures + try: + if ("ENOMEM" in str(e)) or isinstance(e, MemoryError): + import time # type: ignore + _NEXT_ALLOWED_SEND_TS = time.time() + 30 + except: + pass print("Discord webhook exception:", e) return False @@ -76,7 +97,7 @@ def send_discord_message(message, username="Auto Garden Bot", is_alert=False): pass # Free refs and force GC try: - del resp, body_bytes + del resp, body_bytes, requests except: pass try: diff --git a/main.py b/main.py index 4891bb6..99fe67a 100644 --- a/main.py +++ b/main.py @@ -202,6 +202,7 @@ if wifi and wifi.isconnected(): # Send startup notification to Discord (with timeout, non-blocking) try: + gc.collect() # free heap before HTTPS success = discord_webhook.send_discord_message(f"Pico W online at http://{ifconfig[0]} ✅") if success: print("Discord startup notification sent")