Skip to content

feat(executor): add async function and method execution support#42

Merged
deanq merged 6 commits intomainfrom
deanq/ae-1469-execute-async-and-non-for-remote
Nov 14, 2025
Merged

feat(executor): add async function and method execution support#42
deanq merged 6 commits intomainfrom
deanq/ae-1469-execute-async-and-non-for-remote

Conversation

@deanq
Copy link
Contributor

@deanq deanq commented Nov 14, 2025

Complements runpod/flash#112

Add support for executing both sync and async functions/methods in
FunctionExecutor and ClassExecutor. Uses inspect.iscoroutinefunction()
to detect async callables and asyncio.run() to execute them.

Changes:

  • FunctionExecutor: Added async function support with detection and execution
  • ClassExecutor: Added async method support with same pattern
  • Comprehensive test coverage for async execution patterns including:
    • Basic async functions/methods
    • Async with await operations
    • Dict returns (GPU worker pattern)
    • Instance persistence across async calls
    • Mixed sync/async methods in same class
  • Added DEVELOPMENT.md guide

Add support for executing both sync and async functions/methods in
FunctionExecutor and ClassExecutor. Uses inspect.iscoroutinefunction()
to detect async callables and asyncio.run() to execute them.

Changes:
- FunctionExecutor: Added async function support with detection and execution
- ClassExecutor: Added async method support with same pattern
- Comprehensive test coverage for async execution patterns including:
  - Basic async functions/methods
  - Async with await operations
  - Dict returns (GPU worker pattern)
  - Instance persistence across async calls
  - Mixed sync/async methods in same class
@deanq deanq requested review from Copilot and jhcipar November 14, 2025 06:00
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds support for executing both synchronous and asynchronous functions and methods in the worker-tetra execution engine. The implementation uses inspect.iscoroutinefunction() to detect async callables and asyncio.run() to execute them, enabling GPU workers and other use cases that require async execution patterns.

Key Changes:

  • Added async execution support to FunctionExecutor and ClassExecutor with automatic detection
  • Comprehensive test coverage for async patterns including await operations, dict returns, and mixed sync/async methods
  • Added DEVELOPMENT.md guide for contributors

Reviewed Changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/function_executor.py Added async function detection and execution using inspect.iscoroutinefunction() and asyncio.run()
src/class_executor.py Added async method detection and execution with same pattern as function executor
tests/unit/test_function_executor.py Added comprehensive test suite for async function execution patterns
tests/unit/test_class_executor.py Added comprehensive test suite for async method execution with instance persistence
DEVELOPMENT.md Added complete developer guide covering setup, workflow, testing, and contribution guidelines

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Address PR #42 Copilot feedback about asyncio.run() usage.

The previous implementation used asyncio.run() unconditionally, which
raises RuntimeError when called from within a running event loop
(e.g., nested async calls). This could break in scenarios where:
- Handler becomes async in the future
- Users nest remote function calls
- Execution happens in unexpected async contexts

Changes:
- Detect running event loop with asyncio.get_running_loop()
- Use asyncio.run() when no loop is running (current path)
- Use loop.run_until_complete() when loop exists
- Applies to both FunctionExecutor and ClassExecutor

This future-proofs the async execution logic while maintaining
backward compatibility with current synchronous execution context.

Addresses: #42 (comment)
Addresses: #42 (comment)
@deanq deanq requested a review from Copilot November 14, 2025 06:32
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Address PR #42 Copilot feedback (round 2) about async/await architecture.

Root cause: Handler is async (RunPod supports async handlers) which means
an event loop is running when executors execute. Using loop.run_until_complete()
from within a running loop causes deadlock.

Solution: Make entire execution chain async with proper await:
- handler (async) → ExecuteFunction (async) → executors (async) → user funcs

Changes:
- FunctionExecutor.execute(): Made async, await async functions directly
- ClassExecutor.execute_class_method(): Made async, await async methods directly
- RemoteExecutor: Added await to executor calls
- All tests: Made async and added await to executor calls

This eliminates event loop conflicts by using proper async/await chain
instead of trying to manage event loops manually. Works correctly with
RunPod's async handler support.

Fixes: #42 (comment)
Fixes: #42 (comment)
Addresses: Copilot follow-up comments about loop.run_until_complete() deadlock
@deanq deanq merged commit 6b19ce6 into main Nov 14, 2025
12 checks passed
@deanq deanq deleted the deanq/ae-1469-execute-async-and-non-for-remote branch November 14, 2025 18:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants