Skip to content

Commit da7a290

Browse files
committed
fix(bigtable): address remaining accelerator daemon review comments
Change-Id: I3346fce33de1069f27e08e78691c104a169c886b
1 parent 3d3a2cb commit da7a290

1 file changed

Lines changed: 27 additions & 27 deletions

File tree

  • packages/google-cloud-bigtable/google/cloud/bigtable/data/_accelerator

‎packages/google-cloud-bigtable/google/cloud/bigtable/data/_accelerator/_daemon.py‎

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import subprocess
3131
import tempfile
3232
import time
33-
import typing
3433
from typing import Sequence
3534

3635
# Environment variable that overrides the bundled binary location. Primarily
@@ -51,11 +50,6 @@
5150
_SIGKILL_GRACE_SECONDS = 2.0
5251

5352

54-
def _default_binary_path() -> str | None:
55-
bundled = os.path.join(os.path.dirname(__file__), _DEFAULT_BIN_RELATIVE_PATH)
56-
return bundled if os.path.isfile(bundled) else None
57-
58-
5953
def _resolve_binary_path(explicit_path: str | None = None) -> str:
6054
"""Resolve the daemon binary path, validating that it is a regular file.
6155
@@ -78,8 +72,8 @@ def _resolve_binary_path(explicit_path: str | None = None) -> str:
7872
f"{_BIN_ENV_VAR}={override!r} does not point at a regular file"
7973
)
8074
return override
81-
bundled = _default_binary_path()
82-
if bundled is None:
75+
bundled = os.path.join(os.path.dirname(__file__), _DEFAULT_BIN_RELATIVE_PATH)
76+
if not os.path.isfile(bundled):
8377
raise FileNotFoundError(
8478
"No accelerator binary found. Set the "
8579
f"{_BIN_ENV_VAR} env var to a daemon binary path, or install a "
@@ -134,7 +128,6 @@ def __init__(
134128
self._tempdir: str | None = None
135129
self._uds_path: str | None = None
136130
self._log_path: str | None = None
137-
self._log_file: "typing.IO[bytes] | None" = None
138131
self._proc: subprocess.Popen[bytes] | None = None
139132

140133
def __enter__(self) -> "AcceleratorDaemon":
@@ -190,13 +183,16 @@ def start(self) -> None:
190183
# stays a PIPE — closing it is how close() signals the daemon to shut
191184
# down.
192185
self._log_path = os.path.join(self._tempdir, "daemon.log")
193-
self._log_file = open(self._log_path, "wb")
186+
# The log file handle only needs to live long enough for Popen to dup
187+
# it into the child, so it stays local to start() rather than being an
188+
# attribute. Startup failures read the tail back from the path.
189+
log_file = open(self._log_path, "wb")
194190
argv = [self._binary_path, "--uds-path", self._uds_path, *self._cli_flags]
195191
try:
196192
self._proc = subprocess.Popen(
197193
argv,
198194
stdin=subprocess.PIPE,
199-
stdout=self._log_file,
195+
stdout=log_file,
200196
stderr=subprocess.STDOUT,
201197
close_fds=True,
202198
)
@@ -208,11 +204,13 @@ def start(self) -> None:
208204
finally:
209205
# Whether or not the spawn succeeded, the parent no longer needs its
210206
# copy of the log fd: on success the child holds its own dup, and on
211-
# failure there is nothing to keep open. Startup failures read the
212-
# tail back from the path.
213-
self._close_log_file()
207+
# failure there is nothing to keep open.
208+
try:
209+
log_file.close()
210+
except OSError:
211+
pass
214212
try:
215-
self._wait_until_ready()
213+
self._wait_until_ready(self._startup_timeout)
216214
except BaseException:
217215
self._force_kill()
218216
self._cleanup_tempdir()
@@ -242,13 +240,17 @@ def close(self) -> None:
242240
self._wait_for_exit(_SIGKILL_GRACE_SECONDS)
243241
finally:
244242
self._proc = None
245-
self._close_log_file()
246243
self._cleanup_tempdir()
247244

248-
def _wait_until_ready(self) -> None:
245+
def _wait_until_ready(self, timeout: float) -> None:
246+
"""Poll until the UDS accepts a connection, the child dies, or timeout.
247+
248+
Raises RuntimeError if the daemon exits during startup or does not
249+
become connectable within ``timeout`` seconds.
250+
"""
249251
if self._proc is None or self._uds_path is None:
250252
raise RuntimeError("AcceleratorDaemon._wait_until_ready() before spawn")
251-
deadline = time.monotonic() + self._startup_timeout
253+
deadline = time.monotonic() + timeout
252254
while time.monotonic() < deadline:
253255
exit_code = self._proc.poll()
254256
if exit_code is not None:
@@ -269,7 +271,7 @@ def _wait_until_ready(self) -> None:
269271
log_tail = self._read_log_tail()
270272
raise RuntimeError(
271273
"Accelerator daemon did not become ready within "
272-
f"{self._startup_timeout}s. log: {log_tail!r}"
274+
f"{timeout}s. log: {log_tail!r}"
273275
)
274276

275277
def _read_log_tail(self, max_bytes: int = 4096) -> str:
@@ -296,15 +298,11 @@ def _read_log_tail(self, max_bytes: int = 4096) -> str:
296298
return ""
297299
return data.decode("utf-8", errors="replace")
298300

299-
def _close_log_file(self) -> None:
300-
if self._log_file is not None:
301-
try:
302-
self._log_file.close()
303-
except OSError:
304-
pass
305-
self._log_file = None
306-
307301
def _wait_for_exit(self, timeout: float) -> bool:
302+
"""Wait up to ``timeout`` seconds for the child to exit.
303+
304+
Returns True if it has exited (or there is no child), False on timeout.
305+
"""
308306
if self._proc is None:
309307
return True
310308
try:
@@ -314,6 +312,7 @@ def _wait_for_exit(self, timeout: float) -> bool:
314312
return False
315313

316314
def _force_kill(self) -> None:
315+
"""SIGKILL the child and reap it; a no-op if it is already gone."""
317316
if self._proc is None or self._proc.poll() is not None:
318317
return
319318
try:
@@ -326,6 +325,7 @@ def _force_kill(self) -> None:
326325
pass
327326

328327
def _cleanup_tempdir(self) -> None:
328+
"""Remove the tempdir holding the socket and log; clear derived paths."""
329329
if self._tempdir is not None and os.path.isdir(self._tempdir):
330330
shutil.rmtree(self._tempdir, ignore_errors=True)
331331
self._tempdir = None

0 commit comments

Comments
 (0)