bitbake: sigen: Avoid bitbake abort with EOFerror from an incomplete hashserv communication

The issue itself is sporadic but aborts the build with an uncaught exception.

The stack trace of python calls that resulted in this exception/failure was:
File: 'exec_func_python() autogenerated', lineno: 2, function: <module>
     0001:
 *** 0002:sstate_report_unihash(d)
     0003:
File: '(...)/poky/meta/classes/sstate.bbclass', lineno: 882, function: sstate_report_unihash
     0878:    report_unihash = getattr(bb.parse.siggen, 'report_unihash', None)
     0879:
     0880:    if report_unihash:
     0881:        ss = sstate_state_fromvars(d)
 *** 0882:        report_unihash(os.getcwd(), ss['task'], d)
     0883:}
     0884:
     0885:#
     0886:# Shell function to decompress and prepare a package for installation
File: '(...)/poky/lib/bb/siggen.py', lineno: 651, function: report_unihash
     0647:                method = self.method
     0648:                if tid in self.extramethod:
     0649:                    method = method + self.extramethod[tid]
     0650:
 *** 0651:                data = self.client().report_unihash(taskhash, method, outhash, unihash, extra_data)
     0652:                new_unihash = data['unihash']
     0653:
     0654:                if new_unihash != unihash:
     0655:                    hashequiv_logger.debug('Task %s unihash changed %s -> %s by server %s' % (taskhash, unihash, new_unihash, self.server))
File: '(...)/poky/lib/bb/asyncrpc/client.py', lineno: 139, function: wrapper
     0135:        pass
     0136:
     0137:    def _get_downcall_wrapper(self, downcall):
     0138:        def wrapper(*args, **kwargs):
 *** 0139:            return self.loop.run_until_complete(downcall(*args, **kwargs))
     0140:
     0141:        return wrapper
     0142:
     0143:    def _add_methods(self, *methods):
File: '/usr/lib/python3.9/asyncio/base_events.py', lineno: 642, function: run_until_complete
     0638:            future.remove_done_callback(_run_until_complete_cb)
     0639:        if not future.done():
     0640:            raise RuntimeError('Event loop stopped before Future completed.')
     0641:
 *** 0642:        return future.result()
     0643:
     0644:    def stop(self):
     0645:        """Stop running the event loop.
     0646:
File: '(...)/poky/lib/hashserv/client.py', lineno: 70, function: report_unihash
     0066:        m["taskhash"] = taskhash
     0067:        m["method"] = method
     0068:        m["outhash"] = outhash
     0069:        m["unihash"] = unihash
 *** 0070:        return await self.invoke({"report": m})
     0071:
     0072:    async def report_unihash_equiv(self, taskhash, method, unihash, extra={}):
     0073:        await self._set_mode(self.MODE_NORMAL)
     0074:        m = extra.copy()
File: '(...)/poky/lib/bb/asyncrpc/client.py', lineno: 104, function: invoke
     0100:        async def proc():
     0101:            await self.socket.send_message(msg)
     0102:            return await self.socket.recv_message()
     0103:
 *** 0104:        return await self._send_wrapper(proc)
     0105:
     0106:    async def ping(self):
     0107:        return await self.invoke({"ping": {}})
     0108:
File: '(...)/poky/lib/bb/asyncrpc/client.py', lineno: 82, function: _send_wrapper
     0078:    async def _send_wrapper(self, proc):
     0079:        count = 0
     0080:        while True:
     0081:            try:
 *** 0082:                await self.connect()
     0083:                return await proc()
     0084:            except (
     0085:                OSError,
     0086:                ConnectionError,
File: '(...)/poky/lib/bb/asyncrpc/client.py', lineno: 70, function: connect
     0066:        await self.socket.send("")
     0067:
     0068:    async def connect(self):
     0069:        if self.socket is None:
 *** 0070:            self.socket = await self._connect_sock()
     0071:            await self.setup_connection()
     0072:
     0073:    async def close(self):
     0074:        if self.socket is not None:
File: '(...)/poky/lib/bb/asyncrpc/client.py', lineno: 55, function: connect_sock
     0051:        import websockets
     0052:
     0053:        async def connect_sock():
     0054:            try:
 *** 0055:                websocket = await websockets.connect(uri, ping_interval=None)
     0056:            except (OSError, asyncio.exceptions.TimeoutError, websockets.InvalidHandshake, websockets.InvalidURI) as exc:
     0057:                raise ConnectionError("Could not connect to websocket: %s" % exc) from exc
     0058:            return WebsocketConnection(websocket, self.timeout)
     0059:
File: '/usr/local/lib/python3.9/dist-packages/websockets/asyncio/client.py', lineno: 444, function: __await_impl__
     0440:            async with asyncio_timeout(self.open_timeout):
     0441:                for _ in range(MAX_REDIRECTS):
     0442:                    self.connection = await self.create_connection()
     0443:                    try:
 *** 0444:                        await self.connection.handshake(*self.handshake_args)
     0445:                    except asyncio.CancelledError:
     0446:                        self.connection.close_transport()
     0447:                        raise
     0448:                    except Exception as exc:
File: '/usr/local/lib/python3.9/dist-packages/websockets/asyncio/client.py', lineno: 104, function: handshake
     0100:        # receiving a response, when the response cannot be parsed, or when the
     0101:        # response fails the handshake.
     0102:
     0103:        if self.protocol.handshake_exc is not None:
 *** 0104:            raise self.protocol.handshake_exc
     0105:
     0106:    def process_event(self, event: Event) -> None:
     0107:        """
     0108:        Process one incoming event.
File: '/usr/local/lib/python3.9/dist-packages/websockets/client.py', lineno: 315, function: parse
     0311:
     0312:    def parse(self) -> Generator[None]:
     0313:        if self.state is CONNECTING:
     0314:            try:
 *** 0315:                response = yield from Response.parse(
     0316:                    self.reader.read_line,
     0317:                    self.reader.read_exact,
     0318:                    self.reader.read_to_eof,
     0319:                )
File: '/usr/local/lib/python3.9/dist-packages/websockets/http11.py', lineno: 238, function: parse
     0234:
     0235:        try:
     0236:            status_line = yield from parse_line(read_line)
     0237:        except EOFError as exc:
 *** 0238:            raise EOFError("connection closed while reading HTTP status line") from exc
     0239:
     0240:        try:
     0241:            protocol, raw_status_code, raw_reason = status_line.split(b" ", 2)
     0242:        except ValueError:  # not enough values to unpack (expected 3, got 1-2)
Exception: EOFError: connection closed while reading HTTP status line

(Bitbake rev: 5ba7c2f0797a72536a81f57276d4e5c75f23011c)

Signed-off-by: Pedro Ferreira <Pedro.Silva.Ferreira@criticaltechworks.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Pedro Ferreira
2025-07-22 09:27:35 +01:00
committed by Richard Purdie
parent c54fbf6761
commit 921c46de4f

View File

@@ -708,7 +708,7 @@ class SignatureGeneratorUniHashMixIn(object):
try:
with self.client() as client:
unihashes = client.get_unihash_batch((self._get_method(tid), self.taskhash[tid]) for tid in query_tids)
except (ConnectionError, FileNotFoundError) as e:
except (ConnectionError, FileNotFoundError, EOFError) as e:
bb.warn('Error contacting Hash Equivalence Server %s: %s' % (self.server, str(e)))
for idx, tid in enumerate(query_tids):
@@ -817,7 +817,7 @@ class SignatureGeneratorUniHashMixIn(object):
d.setVar('BB_UNIHASH', new_unihash)
else:
hashequiv_logger.debug('Reported task %s as unihash %s to %s' % (taskhash, unihash, self.server))
except (ConnectionError, FileNotFoundError) as e:
except (ConnectionError, FileNotFoundError, EOFError) as e:
bb.warn('Error contacting Hash Equivalence Server %s: %s' % (self.server, str(e)))
finally:
if sigfile:
@@ -859,7 +859,7 @@ class SignatureGeneratorUniHashMixIn(object):
# TODO: What to do here?
hashequiv_logger.verbose('Task %s unihash reported as unwanted hash %s' % (tid, finalunihash))
except (ConnectionError, FileNotFoundError) as e:
except (ConnectionError, FileNotFoundError, EOFError) as e:
bb.warn('Error contacting Hash Equivalence Server %s: %s' % (self.server, str(e)))
return False