Skip to content

Commit ebc8c6c

Browse files
authored
fix: [precaution fix] Capture Python futures while running in the background (#365)
* Capture futures while running in background * Scoped defer background future removal * Use pybind11 provided python set
1 parent 27f04d1 commit ebc8c6c

File tree

2 files changed

+43
-21
lines changed

2 files changed

+43
-21
lines changed

src/pb_stub.cc

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -107,27 +107,8 @@ PyDefaultArgumentToMutableType(const py::object& argument)
107107
void
108108
AsyncEventFutureDoneCallback(const py::object& py_future)
109109
{
110-
// TODO: Why using `py_future.result()` with error hangs on exit?
111-
try {
112-
py::object exception = py_future.attr("exception")();
113-
if (!py::isinstance<py::none>(exception)) {
114-
std::string err_msg = "";
115-
py::object traceback = py::module_::import("traceback")
116-
.attr("TracebackException")
117-
.attr("from_exception")(exception)
118-
.attr("format")();
119-
for (py::handle line : traceback) {
120-
err_msg += py::str(line);
121-
}
122-
LOG_ERROR << err_msg;
123-
}
124-
}
125-
catch (const PythonBackendException& pb_exception) {
126-
LOG_ERROR << pb_exception.what();
127-
}
128-
catch (const py::error_already_set& error) {
129-
LOG_ERROR << error.what();
130-
}
110+
std::unique_ptr<Stub>& stub = Stub::GetOrCreateInstance();
111+
stub->BackgroundFutureDone(py_future);
131112
}
132113

133114
void
@@ -556,6 +537,7 @@ Stub::Initialize(bi::managed_external_buffer::handle_t map_handle)
556537
c_python_backend_utils.attr("shared_memory") = py::cast(shm_pool_.get());
557538

558539
async_event_loop_ = py::none();
540+
background_futures_ = py::set();
559541

560542
py::object TritonPythonModel = sys.attr("TritonPythonModel");
561543
deserialize_bytes_ = python_backend_utils.attr("deserialize_bytes_tensor");
@@ -838,11 +820,47 @@ Stub::RunCoroutine(py::object coroutine, bool in_background)
838820
py_future.attr("add_done_callback")(
839821
py::module_::import("c_python_backend_utils")
840822
.attr("async_event_future_done_callback"));
823+
background_futures_.attr("add")(py_future);
841824
return py::none();
842825
}
843826
return py_future.attr("result")();
844827
}
845828

829+
void
830+
Stub::BackgroundFutureDone(const py::object& py_future)
831+
{
832+
ScopedDefer _([this, &py_future] {
833+
// Remove future from background
834+
try {
835+
background_futures_.attr("remove")(py_future);
836+
}
837+
catch (const py::error_already_set& error) {
838+
LOG_ERROR << "Cannot remove future from background; " << error.what();
839+
}
840+
});
841+
// TODO: Why using `py_future.result()` with error hangs on exit?
842+
try {
843+
py::object exception = py_future.attr("exception")();
844+
if (!py::isinstance<py::none>(exception)) {
845+
std::string err_msg = "";
846+
py::object traceback = py::module_::import("traceback")
847+
.attr("TracebackException")
848+
.attr("from_exception")(exception)
849+
.attr("format")();
850+
for (py::handle line : traceback) {
851+
err_msg += py::str(line);
852+
}
853+
LOG_ERROR << err_msg;
854+
}
855+
}
856+
catch (const PythonBackendException& pb_exception) {
857+
LOG_ERROR << pb_exception.what();
858+
}
859+
catch (const py::error_already_set& error) {
860+
LOG_ERROR << error.what();
861+
}
862+
}
863+
846864
void
847865
Stub::UpdateHealth()
848866
{
@@ -923,6 +941,7 @@ Stub::~Stub()
923941
{
924942
py::gil_scoped_acquire acquire;
925943
async_event_loop_ = py::none();
944+
background_futures_ = py::none();
926945
model_instance_ = py::none();
927946
}
928947
stub_instance_.reset();

src/pb_stub.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ class Stub {
260260

261261
py::object RunCoroutine(py::object coroutine, bool in_background);
262262

263+
void BackgroundFutureDone(const py::object& py_future);
264+
263265
/// Get the memory manager message queue
264266
std::unique_ptr<MessageQueue<uint64_t>>& MemoryManagerQueue();
265267

@@ -367,6 +369,7 @@ class Stub {
367369
py::object deserialize_bytes_;
368370
py::object serialize_bytes_;
369371
py::object async_event_loop_;
372+
py::object background_futures_;
370373
std::unique_ptr<MessageQueue<bi::managed_external_buffer::handle_t>>
371374
stub_message_queue_;
372375
std::unique_ptr<MessageQueue<bi::managed_external_buffer::handle_t>>

0 commit comments

Comments
 (0)