Как настроить однопоточный веб-сервер Rust с использованием PyO3 с обратным вызовом в Python? - PullRequest
0 голосов
/ 27 января 2020

Я хочу иметь возможность сделать что-то подобное с Python:

import web_server  # Rust based web-server

def callback():
  return "Hello world!"

web_server.run(callback)

Где web_server.run запустит однопоточный веб-сервер Rust и ответит значением, полученным от Python обратный вызов.

Я настраиваю модуль и работаю так:

#[pyfunction]
fn run(py: Python<'static>, callback: PyObject) -> PyResult<()> {
    main(py, callback);
    Ok(())
}

/// This module is a python module implemented in Rust.
#[pymodule]
fn web_server(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_wrapped(wrap_pyfunction!(run))?;
    Ok(())
}

Проблема в том, что я не контролирую время жизни обратного вызова, поэтому, когда я пытаюсь сделать сервис, использующий что-то вроде Hyper:

fn main(py: Python<'static>, callback: PyObject) {
    let borrowed_callback = &callback;

    // Configure a runtime that runs everything on the current thread
    let mut rt = tokio::runtime::Builder::new()
        .enable_all()
        .basic_scheduler()
        .build()
        .expect("build runtime")

    let local = tokio::task::LocalSet::new();
    local.block_on(&mut rt, async {
        let make_service = make_service_fn(move |_| {
            async move {
                Ok::<_, Error>(service_fn(move |_| {
                    let value: String = borrowed_callback
                        .call(py, (), None)
                        .unwrap()
                        .extract(py)
                        .unwrap();
                    async move { Ok::<_, Error>(Response::new(Body::from(value))) }
                }))
            }
        });

        let server = Server::bind(&addr).executor(LocalExec).serve(make_service);
        ...
    }
}

Я получаю следующее:

pyo3::object::PyObject
`callback` does not live long enough

borrowed value does not live long enoughrustc(E0597)
lib.rs(13, 29): borrowed value does not live long enough
lib.rs(33, 13): returning this value requires that `callback` is borrowed for `'static`
lib.rs(53, 1): `callback` dropped here while still borrowed

Я довольно новичок в Rust, поэтому не уверен, что что-то упустил просто здесь, или если это просто не реально сейчас. Поскольку я поддерживаю работу веб-сервера в течение всего срока службы программы, похоже, что callback никогда не следует очищать с помощью Python G C, но я не вижу пути к express, чтобы время жизни объекта 'static в PyO3.

...