Skip to content

Commit 1d99a70

Browse files
bkeryanVikram S A
andauthored
[releases/1.1] ni_measurementlink_service: Launch discovery service just-in-time before registering a measurement service (#317)
ni_measurementlink_service: Launch discovery service just-in-time before registering a measurement service. (#290) * discovery_client: Launch discovery service just-in-time * discovery_client: add comments to functions * discovery_client: Fix lint errors. * discovery_client: Fix function docstring and type hint * discovery_client: Wait for key file existence and time out when 30 seconds elapse * discovery_client: Replace polling2 module with time module * discovery_client: Added service already running functionality * discovery_client: Refactor open method with write permission. Co-authored-by: Brad Keryan <brad.keryan@ni.com> --------- Co-authored-by: Brad Keryan <brad.keryan@ni.com> (cherry picked from commit 5af9b2f) Co-authored-by: Vikram S A <vikram.avudaiappan@ni.com>
1 parent 7b3d633 commit 1d99a70

1 file changed

Lines changed: 71 additions & 0 deletions

File tree

ni_measurementlink_service/_internal/discovery_client.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
import logging
55
import os
66
import pathlib
7+
import subprocess
78
import sys
9+
import time
810
import typing
911
from typing import Optional
1012

@@ -26,6 +28,9 @@
2628

2729
_logger = logging.getLogger(__name__)
2830

31+
_START_SERVICE_TIMEOUT = 30.0
32+
_START_SERVICE_POLLING_INTERVAL = 100e-3
33+
2934

3035
class ServiceLocation(typing.NamedTuple):
3136
"""Represents the location of a service."""
@@ -204,12 +209,78 @@ def resolve_service(self, provided_interface: str, service_class: str = "") -> S
204209

205210
def _get_discovery_service_address() -> str:
206211
key_file_path = _get_key_file_path()
212+
_ensure_discovery_service_started(key_file_path)
207213
_logger.debug("Discovery service key file path: %s", key_file_path)
208214
with _open_key_file(str(key_file_path)) as key_file:
209215
key_json = json.load(key_file)
210216
return "localhost:" + key_json["InsecurePort"]
211217

212218

219+
def _ensure_discovery_service_started(key_file_path: pathlib.Path) -> None:
220+
"""Check whether discovery service already running, if not start the discovery service."""
221+
if _service_already_running(key_file_path):
222+
return
223+
224+
exe_file_path = _get_discovery_service_location()
225+
_start_service(exe_file_path, key_file_path)
226+
227+
228+
def _get_discovery_service_location() -> pathlib.PurePath:
229+
"""Gets the location of the discovery service process executable."""
230+
registration_json_path = _get_registration_json_file_path()
231+
registration_json_obj = json.loads(registration_json_path.read_text())
232+
return registration_json_path.parent / registration_json_obj["discovery"]["path"]
233+
234+
235+
def _get_registration_json_file_path() -> pathlib.Path:
236+
if sys.platform == "win32":
237+
return (
238+
pathlib.Path(os.environ["ProgramW6432"])
239+
/ "National Instruments"
240+
/ "Shared"
241+
/ "MeasurementLink"
242+
/ "MeasurementLinkServices.json"
243+
)
244+
else:
245+
raise NotImplementedError("Platform not supported")
246+
247+
248+
def _key_file_exists(key_file_path: pathlib.Path) -> bool:
249+
return key_file_path.is_file() and key_file_path.stat().st_size > 0
250+
251+
252+
def _start_service(exe_file_path: pathlib.PurePath, key_file_path: pathlib.Path) -> None:
253+
"""Starts the service at the specified path and wait for the service to get up and running."""
254+
subprocess.Popen([exe_file_path], cwd=exe_file_path.parent)
255+
# After the execution of process, check for key file existence in the path
256+
# stop checking after 30 seconds have elapsed and throw error
257+
timeout_time = time.time() + _START_SERVICE_TIMEOUT
258+
while True:
259+
try:
260+
with _open_key_file(str(key_file_path)) as _:
261+
return
262+
except IOError:
263+
pass
264+
if time.time() >= timeout_time:
265+
raise TimeoutError("Timed out waiting for discovery service to start")
266+
time.sleep(_START_SERVICE_POLLING_INTERVAL)
267+
268+
269+
def _service_already_running(key_file_path: pathlib.Path) -> bool:
270+
try:
271+
_delete_existing_key_file(key_file_path)
272+
except IOError:
273+
return True
274+
return False
275+
276+
277+
def _delete_existing_key_file(key_file_path: pathlib.Path) -> None:
278+
if _key_file_exists(key_file_path):
279+
with key_file_path.open("w") as _:
280+
pass
281+
key_file_path.unlink()
282+
283+
213284
def _get_key_file_path(cluster_id: Optional[str] = None) -> pathlib.Path:
214285
if cluster_id is not None:
215286
return _get_key_file_directory() / f"DiscoveryService_{cluster_id}.json"

0 commit comments

Comments
 (0)