Skip to content

fix: run dynamo components standalone (1/2) #1560

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

mohammedabdulwahhab
Copy link
Contributor

@mohammedabdulwahhab mohammedabdulwahhab commented Jun 17, 2025

Overview:

Allows components to be run directly with python3 while being inter-operable with dynamo serve

docs: https://github.com/ai-dynamo/dynamo/blob/9e839039cb7ae882c047092bad1da87394f873c9/docs/API/sdk.md#direct-python-invocation

Testing

cd examples
python3 -m hello_world_standalone # start server
python3 -m hello_world_standalone client

closes https://linear.app/nvidia-dynamo/issue/DEP-173/issue-user-should-be-able-to-launch-a-component-using-python3-m

Summary by CodeRabbit

  • New Features

    • Introduced a standalone service serving module for running Dynamo-based services asynchronously.
    • Added example services demonstrating SDK v2 usage, including backend/frontend communication and streaming responses.
    • Enabled automatic injection of runtime context into service constructors for advanced usage patterns.
  • Documentation

    • Added a markdown document outlining SDK v2 design goals, user personas, and usage examples for the new serving framework.

Copy link

copy-pr-bot bot commented Jun 17, 2025

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions github-actions bot added the fix label Jun 17, 2025
@mohammedabdulwahhab mohammedabdulwahhab changed the title fix: fix fix: run components standalone Jun 17, 2025
@mohammedabdulwahhab mohammedabdulwahhab changed the title fix: run components standalone fix: run dynamo components standalone Jun 17, 2025
@mohammedabdulwahhab mohammedabdulwahhab changed the title fix: run dynamo components standalone fix: run dynamo components standalone (1/2) Jun 17, 2025
@mohammedabdulwahhab mohammedabdulwahhab marked this pull request as ready for review June 17, 2025 17:46
return getattr(instance, name)
return None

def get_ep_handlers(endpoints, inner_instance):
Copy link
Contributor

@ishandhanani ishandhanani Jun 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we call this get_endpoint_handlers. EP is very overloaded these days :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


# 6. Finally serve each endpoint
handlers = get_ep_handlers(drt_endpoints, inner_instance)
ep_2_handler = {endpoints[ep_name]: handlers[ep_name] for ep_name in endpoints}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this ep_2_handler?

Copy link
Contributor Author

@mohammedabdulwahhab mohammedabdulwahhab Jun 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mapping between endpoint (from drt) to the actual request handler that should be used to serve it

endpoint = component.endpoint("foo")
handler = # actual function to serve the endpoint with
... # below
endpoint.serve_endpoint(handler)

@ishandhanani
Copy link
Contributor

Does this PR address

#1481 (comment) ?

Copy link
Contributor

coderabbitai bot commented Jun 17, 2025

Walkthrough

The changes introduce a standalone serving mechanism for Dynamo-based services, including a new CLI module, context model, and serving coroutine. Example files demonstrate usage patterns for SDK v2, including context injection and endpoint streaming. Additionally, a markdown document outlines personas and API design proposals for serving components with varying levels of control.

Changes

File(s) Change Summary
deploy/sdk/src/dynamo/sdk/init.py Added import for serve from dynamo.sdk.cli.serve_standalone.
deploy/sdk/src/dynamo/sdk/cli/serve_standalone.py Added new CLI module with DynamoContext model and serve coroutine for asynchronous service serving.
examples/sdk_v2/default.py Added example with Backend and Frontend services, async startup hooks, endpoint streaming, and serve usage.
examples/sdk_v2/mixed.py Added example Router service using injected DynamoContext for dynamic client creation and endpoint streaming.
examples/sdk_v2/v2.md Added markdown document outlining SDK serving personas, usage patterns, and conceptual API design.

Sequence Diagram(s)

sequenceDiagram
    participant User as User Script
    participant Serve as serve()
    participant Service as Service Class
    participant Runtime as Dynamo Runtime
    participant Endpoint as Endpoint Handler

    User->>Serve: Call serve(Service)
    Serve->>Runtime: Initialize or use runtime
    Serve->>Service: Instantiate (inject DynamoContext if needed)
    alt Service defines async_init
        Serve->>Service: Await async_init()
    end
    Serve->>Endpoint: Bind endpoint handlers to Service methods
    Serve->>Runtime: Register endpoint handlers
    Serve->>Endpoint: Start serving endpoints (async)
Loading

Poem

In the meadow of code, a new path unfurled,
With serve and context, a new world is twirled.
Services stream greetings, endpoints take flight,
Examples abound in the soft morning light.
Rabbits rejoice as the SDK grows—
Hopping through docs, where the Dynamo flows!
🐇✨


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (8)
examples/sdk_v2/mixed.py (2)

25-25: Remove unused import.

uvloop is imported but not used.

-    import uvloop

1-38: Apply black formatting.

The code needs to be formatted according to the project's style guide.

Run black examples/sdk_v2/mixed.py to fix formatting issues.

examples/sdk_v2/default.py (2)

77-77: Remove unused import.

uvloop is imported but not used.

-    import uvloop

1-79: Apply black formatting.

The code needs to be formatted according to the project's style guide.

Run black examples/sdk_v2/default.py to fix formatting issues.

deploy/sdk/src/dynamo/sdk/cli/serve_standalone.py (2)

3-3: Remove unused imports.

List and configure_dynamo_logging are imported but not used.

-from typing import List, Any, Dict
+from typing import Any, Dict
-from dynamo.runtime.logging import configure_dynamo_logging

Also applies to: 9-9


1-106: Apply black formatting.

The code needs to be formatted according to the project's style guide.

Run black deploy/sdk/src/dynamo/sdk/cli/serve_standalone.py to fix formatting issues.

examples/sdk_v2/v2.md (2)

93-93: Fix trailing whitespace.

Remove trailing whitespace at the end of line 93.

-``` 
+```

97-98: Fix markdown formatting issues.

  1. Fix list indentation (should be 2 spaces, not 4)
  2. Remove trailing punctuation from heading
 - giving user access to the runtime, component, endpoints without a global dynamo_context dict
-    - user can introspect serve() function to see how this injection is happening
-    - extremely clear when dynamo_context is populated, since it is being injected
+  - user can introspect serve() function to see how this injection is happening
+  - extremely clear when dynamo_context is populated, since it is being injected
-### Persona 3: Power user: Total control over how the endpoints are served and don't want anything to happen automatically. 
+### Persona 3: Power user: Total control over how the endpoints are served and don't want anything to happen automatically

Also applies to: 107-107

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 44c5be7 and 2711016.

📒 Files selected for processing (5)
  • deploy/sdk/src/dynamo/sdk/__init__.py (1 hunks)
  • deploy/sdk/src/dynamo/sdk/cli/serve_standalone.py (1 hunks)
  • examples/sdk_v2/default.py (1 hunks)
  • examples/sdk_v2/mixed.py (1 hunks)
  • examples/sdk_v2/v2.md (1 hunks)
🧰 Additional context used
🪛 Ruff (0.11.9)
deploy/sdk/src/dynamo/sdk/__init__.py

26-26: dynamo.sdk.cli.serve_standalone.serve imported but unused

(F401)

examples/sdk_v2/mixed.py

3-3: Undefined name service

(F821)


12-12: Undefined name async_init

(F821)


17-17: Undefined name endpoint

(F821)


18-18: Undefined name ChatRequest

(F821)


25-25: uvloop imported but unused

Remove unused import: uvloop

(F401)


28-28: Undefined name serve

(F821)

deploy/sdk/src/dynamo/sdk/cli/serve_standalone.py

3-3: typing.List imported but unused

Remove unused import: typing.List

(F401)


9-9: Module level import not at top of file

(E402)


9-9: dynamo.runtime.logging.configure_dynamo_logging imported but unused

Remove unused import: dynamo.runtime.logging.configure_dynamo_logging

(F401)


10-10: Module level import not at top of file

(E402)


11-11: Module level import not at top of file

(E402)


12-12: Module level import not at top of file

(E402)

examples/sdk_v2/default.py

77-77: uvloop imported but unused

Remove unused import: uvloop

(F401)

🪛 GitHub Actions: Pre Merge Validation of (ai-dynamo/dynamo/refs/pull/1560/merge) by mohammedabdulwahhab.
deploy/sdk/src/dynamo/sdk/__init__.py

[error] 21-45: ESLint: dynamo.sdk.cli.serve_standalone.serve imported but unused; consider removing, adding to __all__, or using a redundant alias (F401)


[error] isort formatting check failed. Files were modified to fix import order issues.

examples/sdk_v2/mixed.py

[error] 4-4: ESLint: Undefined name service (F821)


[error] 13-13: ESLint: Undefined name async_init (F821)


[error] 23-23: ESLint: Undefined name endpoint (F821)


[error] 24-24: ESLint: Undefined name ChatRequest (F821)


[error] 35-35: ESLint: Undefined name serve (F821)


[error] black formatting check failed. Files were reformatted to comply with code style.

deploy/sdk/src/dynamo/sdk/cli/serve_standalone.py

[error] 12-14: ESLint: Module level import not at top of file (E402)


[error] black formatting check failed. Files were reformatted to comply with code style.

examples/sdk_v2/default.py

[error] black formatting check failed. Files were reformatted to comply with code style.

examples/sdk_v2/v2.md

[error] trailing-whitespace check failed. Files were modified to remove trailing whitespace.

🪛 Pylint (3.3.7)
examples/sdk_v2/mixed.py

[error] 3-3: Undefined variable 'service'

(E0602)


[error] 15-15: Instance of 'Router' has no 'namespace' member

(E1101)


[error] 17-17: Undefined variable 'endpoint'

(E0602)


[error] 18-18: Undefined variable 'ChatRequest'

(E0602)


[error] 28-28: Undefined variable 'serve'

(E0602)

deploy/sdk/src/dynamo/sdk/cli/serve_standalone.py

[refactor] 20-20: Too few public methods (0/2)

(R0903)


[refactor] 18-18: Too few public methods (0/2)

(R0903)


[error] 76-76: No value for argument 'runtime' in function call

(E1120)

examples/sdk_v2/default.py

[refactor] 21-21: Too few public methods (0/2)

(R0903)


[refactor] 25-25: Too few public methods (0/2)

(R0903)

🪛 GitHub Actions: Copyright Checks
examples/sdk_v2/mixed.py

[error] 1-1: Invalid or missing copyright header detected. Please add the required SPDX copyright and license header.

deploy/sdk/src/dynamo/sdk/cli/serve_standalone.py

[error] 1-1: Invalid or missing copyright header detected. Please add the required SPDX copyright and license header.

🪛 LanguageTool
examples/sdk_v2/v2.md

[uncategorized] ~13-~13: Possible missing comma found.
Context: ...me cases ## Proposal In the following section I'll iterate through variations that sh...

(AI_HYDRA_LEO_MISSING_COMMA)


[style] ~49-~49: Try using a synonym here to strengthen your writing.
Context: ...at do we need to add next? - Ability to give access to the runtime, endpoints, compo...

(GIVE_PROVIDE)


[style] ~98-~98: As an alternative to the over-used intensifier ‘extremely’, consider replacing this phrase.
Context: ...e how this injection is happening - extremely clear when dynamo_context is populated, since...

(EN_WEAK_ADJECTIVE)


[uncategorized] ~101-~101: Did you mean “my”?
Context: ...rve() is still serving my endpoints for me - serve() creates a DynamoContext insta...

(FOR_ME_FOR_MY)


[uncategorized] ~105-~105: Possible missing comma found.
Context: ...hat are facilitating the serving of the component and not have that hidden behind a serve...

(AI_HYDRA_LEO_MISSING_COMMA)


[uncategorized] ~109-~109: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...ything to happen automatically. Wants top level code to use raw bindings to serve compo...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[uncategorized] ~109-~109: The grammatical number of this noun doesn’t look right. Consider replacing it.
Context: ...level code to use raw bindings to serve component. Might also want to pass args and kwarg...

(AI_EN_LECTOR_REPLACEMENT_NOUN_NUMBER)


[uncategorized] ~109-~109: You might be missing the article “the” here.
Context: ... also want to pass args and kwargs from top level to the constructor ```python fro...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

🪛 markdownlint-cli2 (0.17.2)
examples/sdk_v2/v2.md

97-97: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


98-98: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


107-107: Trailing punctuation in heading
Punctuation: '.'

(MD026, no-trailing-punctuation)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Build and Test - vllm
🔇 Additional comments (2)
examples/sdk_v2/default.py (1)

46-46: Update or clarify the comment about dynamo serve.

The comment states this block is run with dynamo serve, but the PR objective is to enable standalone execution with python3 -m. This seems contradictory.

Should this comment be updated to reflect the new standalone serving capability? The main block already uses serve(Backend) for standalone execution.

deploy/sdk/src/dynamo/sdk/cli/serve_standalone.py (1)

37-38: ```shell
#!/bin/bash

Display the serve function including inner worker and its invocation

sed -n '1,200p' deploy/sdk/src/dynamo/sdk/cli/serve_standalone.py

Locate where worker is called within the file

rg -n "await worker" deploy/sdk/src/dynamo/sdk/cli/serve_standalone.py
rg -n "worker(" deploy/sdk/src/dynamo/sdk/cli/serve_standalone.py


</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

@mohammedabdulwahhab
Copy link
Contributor Author

Does this PR address

#1481 (comment) ?

When running components using python3, they don't need any depends statements. Is this what is being asked?

Copy link
Contributor

@biswapanda biswapanda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Let's add a README.md for users
  2. one comment for type safety

"""
sig = inspect.signature(service.inner.__init__)
params = list(sig.parameters.keys())
return len(params) > 1 and params[1] == "dynamo_context"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we introspect type along with variable name - warn if there is a type mismatch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, agreed. I think that's a fix worth keeping

Copy link
Contributor

@biswapanda biswapanda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

parser.add_argument("--name", default="User", help="Name to use (for client)")
args = parser.parse_args()

uvloop.install()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this not be happenign in serve_standalone?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants