Skip to content

Commit

Permalink
Merge pull request #8997 from OpenMined/tauquir/uvicorn-vscode-debugger
Browse files Browse the repository at this point in the history
🚀 Debug Syft nodes in VSCode
  • Loading branch information
rasswanth-s authored Jul 3, 2024
2 parents 9426b61 + 16a154d commit aa5f57b
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 5 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
.idea/
.mypy_cache
.python-version
.vscode/
.vscode/*
!.vscode/launch.json
.tox/*
.creds
build
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ repos:
exclude: ^(packages/syft/tests/mongomock)
- id: check-json
always_run: true
exclude: ^(packages/grid/frontend/|packages/syft/tests/mongomock)
exclude: ^(packages/grid/frontend/|packages/syft/tests/mongomock|.vscode)
- id: check-added-large-files
always_run: true
exclude: ^(packages/grid/backend/wheels/.*|docs/img/header.png|docs/img/terminalizer.gif)
Expand Down Expand Up @@ -179,7 +179,7 @@ repos:
rev: "v3.0.0-alpha.9-for-vscode"
hooks:
- id: prettier
exclude: ^(packages/grid/helm|packages/grid/frontend/pnpm-lock.yaml|packages/syft/tests/mongomock)
exclude: ^(packages/grid/helm|packages/grid/frontend/pnpm-lock.yaml|packages/syft/tests/mongomock|.vscode)

# - repo: meta
# hooks:
Expand Down
25 changes: 25 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Syft Debugger",
"type": "debugpy",
"request": "attach",
"connect": {
"host": "localhost",
"port": "${input:port}"
}
}
],
"inputs": [
{
"id": "port",
"description": "Port on which the debugger is listening",
"type": "promptString",
"default": "5678"
}
]
}
3 changes: 2 additions & 1 deletion packages/syft/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,12 @@ dev =
%(test_plugins)s
%(telemetry)s
bandit==1.7.8
ruff==0.4.7
debugpy==1.8.2
importlib-metadata==7.1.0
isort==5.13.2
mypy==1.10.0
pre-commit==3.7.1
ruff==0.4.7
safety>=2.4.0b2

telemetry =
Expand Down
38 changes: 37 additions & 1 deletion packages/syft/src/syft/node/server.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# stdlib
from collections.abc import Callable
import multiprocessing
import multiprocessing.synchronize
import os
from pathlib import Path
import platform
Expand Down Expand Up @@ -95,7 +96,28 @@ def app_factory() -> FastAPI:
return app


def run_uvicorn(host: str, port: int, **kwargs: Any) -> None:
def attach_debugger() -> None:
# third party
import debugpy

os.environ["PYDEVD_DISABLE_FILE_VALIDATION"] = "1"
_, debug_port = debugpy.listen(0)
print(
"\nStarting the server with the Python Debugger enabled (`debug=True`).\n"
'To attach the debugger, open the command palette in VSCode and select "Debug: Start Debugging (F5)".\n'
f"Then, enter `{debug_port}` in the port field and press Enter.\n"
)
print(f"Waiting for debugger to attach on port `{debug_port}`...")
debugpy.wait_for_client() # blocks execution until a remote debugger is attached
print("Debugger attached")


def run_uvicorn(
host: str,
port: int,
starting_uvicorn_event: multiprocessing.synchronize.Event,
**kwargs: Any,
) -> None:
if kwargs.get("reset"):
try:
python_pids = find_python_processes_on_port(port)
Expand All @@ -106,6 +128,9 @@ def run_uvicorn(host: str, port: int, **kwargs: Any) -> None:
except Exception: # nosec
print(f"Failed to kill python process on port: {port}")

if kwargs.get("debug"):
attach_debugger()

# Set up all kwargs as environment variables so that they can be accessed in the app_factory function.
env_prefix = AppSettings.model_config.get("env_prefix", "")
for key, value in kwargs.items():
Expand All @@ -120,6 +145,9 @@ def run_uvicorn(host: str, port: int, **kwargs: Any) -> None:
# sys.stdin while running uvicorn programmatically.
sys.stdin = None # type: ignore

# Signal the parent process that we are starting the uvicorn server.
starting_uvicorn_event.set()

# Finally, run the uvicorn server.
uvicorn.run(
"syft.node.server:app_factory",
Expand Down Expand Up @@ -148,7 +176,10 @@ def serve_node(
n_consumers: int = 0,
association_request_auto_approval: bool = False,
background_tasks: bool = False,
debug: bool = False,
) -> tuple[Callable, Callable]:
starting_uvicorn_event = multiprocessing.Event()

# Enable IPython autoreload if dev_mode is enabled.
if dev_mode:
enable_autoreload()
Expand All @@ -171,6 +202,8 @@ def serve_node(
"n_consumers": n_consumers,
"association_request_auto_approval": association_request_auto_approval,
"background_tasks": background_tasks,
"debug": debug,
"starting_uvicorn_event": starting_uvicorn_event,
},
)

Expand All @@ -187,6 +220,9 @@ def start() -> None:
print(f"Starting {name} server on {host}:{port}")
server_process.start()

# Wait for the child process to start uvicorn server before starting the readiness checks.
starting_uvicorn_event.wait()

if tail:
try:
while True:
Expand Down
4 changes: 4 additions & 0 deletions packages/syft/src/syft/orchestra.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ def deploy_to_python(
queue_port: int | None = None,
association_request_auto_approval: bool = False,
background_tasks: bool = False,
debug: bool = False,
) -> NodeHandle:
worker_classes = {
NodeType.DOMAIN: Domain,
Expand Down Expand Up @@ -196,6 +197,7 @@ def deploy_to_python(
"create_producer": create_producer,
"association_request_auto_approval": association_request_auto_approval,
"background_tasks": background_tasks,
"debug": debug,
}

if port:
Expand Down Expand Up @@ -285,6 +287,7 @@ def launch(
queue_port: int | None = None,
association_request_auto_approval: bool = False,
background_tasks: bool = False,
debug: bool = False,
) -> NodeHandle:
if dev_mode is True:
thread_workers = True
Expand Down Expand Up @@ -321,6 +324,7 @@ def launch(
queue_port=queue_port,
association_request_auto_approval=association_request_auto_approval,
background_tasks=background_tasks,
debug=debug,
)
elif deployment_type_enum == DeploymentType.REMOTE:
return deploy_to_remote(
Expand Down

0 comments on commit aa5f57b

Please sign in to comment.