fix(esp32): worker subprocess fallback for esp32_flash_image import
CI's e2e test_hcsr04_simulation.mjs caught the regression introduced by
a3f21a2 (the issue #101 fix). The worker crashes on boot with
Firmware decode error: No module named 'app'
esp32_worker.py runs as a subprocess via subprocess.Popen([sys.executable,
WORKER_PATH, ...]). When Python launches a script directly, sys.path[0]
is the SCRIPT's directory (backend/app/services/), not the backend root.
So `from app.services.esp32_flash_image import pad_to_flash_size` fails
because there is no `app/` under `backend/app/services/`.
esp32_lib_bridge.py wasn't affected because it runs in-process inside
uvicorn, where backend/ is implicitly on sys.path.
Fix: same try/except + importlib fallback the worker already uses for
esp32_i2c_slaves at the top of the file. First try the package import
(works when imported by the bridge's tests or anything else with the
backend root on sys.path), fall back to direct file loading otherwise.
Verified the fallback works in isolation by simulating the subprocess
context (sys.path containing only backend/app/services/) — the package
import fails as expected and the file-load fallback returns a properly
padded 4 MB buffer.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c939005bf7
commit
be0cd514aa
|
|
@ -317,7 +317,20 @@ def main() -> None: # noqa: C901 (complexity OK for inline worker)
|
|||
# The compiler trims trailing 0xFF padding before serializing (issue
|
||||
# #101 — full 4 MB images blew nginx buffers). Re-pad here so QEMU's
|
||||
# MTD layer sees a valid power-of-2 flash size.
|
||||
from app.services.esp32_flash_image import pad_to_flash_size
|
||||
# Imported via fallback because this file runs as a subprocess and
|
||||
# `app.*` is not on sys.path; mirrors the esp32_i2c_slaves pattern
|
||||
# at the top of the file.
|
||||
try:
|
||||
from app.services.esp32_flash_image import pad_to_flash_size # type: ignore[import-not-found]
|
||||
except ImportError:
|
||||
import importlib.util as _ilu, pathlib as _pl
|
||||
_spec = _ilu.spec_from_file_location(
|
||||
'esp32_flash_image',
|
||||
_pl.Path(__file__).parent / 'esp32_flash_image.py',
|
||||
)
|
||||
_mod = _ilu.module_from_spec(_spec) # type: ignore[arg-type]
|
||||
_spec.loader.exec_module(_mod) # type: ignore[union-attr]
|
||||
pad_to_flash_size = _mod.pad_to_flash_size
|
||||
fw_bytes = pad_to_flash_size(base64.b64decode(firmware_b64))
|
||||
tmp = tempfile.NamedTemporaryFile(suffix='.bin', delete=False)
|
||||
tmp.write(fw_bytes)
|
||||
|
|
|
|||
Loading…
Reference in New Issue