-
Notifications
You must be signed in to change notification settings - Fork 42
Fix GitHub issue 280 #330
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
Fix GitHub issue 280 #330
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -86,6 +86,39 @@ Runtime( | |||||||||||||
| ).start() | ||||||||||||||
| ``` | ||||||||||||||
|
|
||||||||||||||
| ### Note on blocking behavior of `Runtime.start()` | ||||||||||||||
|
|
||||||||||||||
| By design, `Runtime.start()` runs the runtime loop indefinitely and will block the main thread when no asyncio event loop is running (e.g., normal Python scripts). In interactive environments that already have an event loop (like Jupyter notebooks), `Runtime.start()` returns an `asyncio.Task` and does not block. | ||||||||||||||
|
|
||||||||||||||
| - If you're in an async/interactive environment (e.g., Jupyter/REPL with a running loop): | ||||||||||||||
|
|
||||||||||||||
| ```python | ||||||||||||||
| # Jupyter/async environment | ||||||||||||||
| runtime = Runtime(namespace="MyProject", name="DataProcessor", nodes=[SampleNode]) | ||||||||||||||
| task = runtime.start() # task is an asyncio.Task running in the background | ||||||||||||||
| # You can continue interacting, and optionally await/cancel the task later | ||||||||||||||
| # await task # if you want to wait on it | ||||||||||||||
| ``` | ||||||||||||||
|
|
||||||||||||||
| - If you need a non-blocking start from a regular sync script, run it in a background thread: | ||||||||||||||
|
|
||||||||||||||
| ```python | ||||||||||||||
| from threading import Thread | ||||||||||||||
|
|
||||||||||||||
| runtime = Runtime(namespace="MyProject", name="DataProcessor", nodes=[SampleNode]) | ||||||||||||||
| Thread(target=runtime.start, daemon=True).start() | ||||||||||||||
| # continue with other work in the main thread | ||||||||||||||
| ``` | ||||||||||||||
NiveditJain marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
|
|
||||||||||||||
| - Alternatively, from an async context you can offload to a thread: | ||||||||||||||
|
|
||||||||||||||
| ```python | ||||||||||||||
| import asyncio | ||||||||||||||
|
|
||||||||||||||
| runtime = Runtime(namespace="MyProject", name="DataProcessor", nodes=[SampleNode]) | ||||||||||||||
| await asyncio.to_thread(runtime.start) | ||||||||||||||
| ``` | ||||||||||||||
|
Comment on lines
+118
to
+120
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This example contradicts “offload to a thread” by awaiting the call. Schedule it as a background task instead. - await asyncio.to_thread(runtime.start)
+ task = asyncio.create_task(asyncio.to_thread(runtime.start))
+ # optionally await/cancel later📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
|
|
||||||||||||||
| ## Next Steps | ||||||||||||||
|
|
||||||||||||||
| Now that you have the basics, explore: | ||||||||||||||
|
|
||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -59,6 +59,36 @@ Runtime( | |||||||||||||||||||||||||||||
| ).start() | ||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ### Note on blocking behavior of `Runtime.start()` | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| `Runtime.start()` blocks the main thread when no asyncio event loop is running (typical Python scripts). In environments with an active event loop (e.g., Jupyter), it returns an `asyncio.Task` and does not block. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| - Jupyter/interactive (non-blocking): | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ```python | ||||||||||||||||||||||||||||||
| runtime = Runtime(namespace="MyProject", name="DataProcessor", nodes=[SampleNode]) | ||||||||||||||||||||||||||||||
| task = runtime.start() # background asyncio.Task | ||||||||||||||||||||||||||||||
| # await task # optionally wait on it later | ||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| - Regular sync script (non-blocking via thread): | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ```python | ||||||||||||||||||||||||||||||
| from threading import Thread | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| runtime = Runtime(namespace="MyProject", name="DataProcessor", nodes=[SampleNode]) | ||||||||||||||||||||||||||||||
| Thread(target=runtime.start, daemon=True).start() | ||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||
|
Comment on lines
+74
to
+81
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Keep a thread handle; call out daemon trade-offs Create and name the thread so users can observe/coordinate shutdown. Daemon threads can terminate abruptly; a handle enables optional joining. - Thread(target=runtime.start, daemon=True).start()
+ t = Thread(target=runtime.start, name="exosphere-runtime", daemon=True)
+ t.start()
+ # on shutdown you may: t.join(timeout=5)📝 Committable suggestion
Suggested change
🧰 Tools🪛 LanguageTool[grammar] ~74-~74: Use correct spacing (QB_NEW_EN_OTHER_ERROR_IDS_5) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| - From async code (offload to a thread): | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ```python | ||||||||||||||||||||||||||||||
| import asyncio | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| runtime = Runtime(namespace="MyProject", name="DataProcessor", nodes=[SampleNode]) | ||||||||||||||||||||||||||||||
| await asyncio.to_thread(runtime.start) | ||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||
|
Comment on lines
+85
to
+90
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Awaiting
- await asyncio.to_thread(runtime.start)
+ task = asyncio.create_task(asyncio.to_thread(runtime.start))
+ # optionally: await task # later, if you want to join/cancelAlternative: 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ## Environment Configuration | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| The SDK requires the following environment variables for authentication with ExosphereHost: | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Background-thread sample: capture the thread handle and note shutdown behavior
Starting a daemon thread is fine for quickstarts, but users should keep a handle for observability/shutdown. Replace the one-liner with two lines.
If
Runtime.start()truly returns an asyncio.Task when a loop is running, please verify in code (e.g., look for loop-detection andasyncio.create_taskpaths) so the note remains accurate across releases.📝 Committable suggestion
🧰 Tools
🪛 LanguageTool
[grammar] ~74-~74: There might be a problem here.
Context: ...ive loop (e.g., Jupyter), it returns an
asyncio.Taskand does not block. For non-blocking usage ...(QB_NEW_EN_MERGED_MATCH)
[grammar] ~74-~74: Use correct spacing
Context: ..., you can run it in a background thread:
python from threading import Thread runtime = Runtime(name="my-first-runtime", namespace="hello-world", nodes=[MyFirstNode]) Thread(target=runtime.start, daemon=True).start()- ### Define your first graph Graphs are ...(QB_NEW_EN_OTHER_ERROR_IDS_5)
🤖 Prompt for AI Agents