@@ -107,27 +107,8 @@ PyDefaultArgumentToMutableType(const py::object& argument)
107107void
108108AsyncEventFutureDoneCallback (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
133114void
@@ -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+
846864void
847865Stub::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 ();
0 commit comments