首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将actix-web作为Windows服务运行的问题

将actix-web作为Windows服务运行的问题
EN

Stack Overflow用户
提问于 2019-08-21 01:15:19
回答 1查看 827关注 0票数 1

我试图使用窗口服务运行actix应用程序。它提供了一个很好的API,并且大部分都能工作。我可以开始我的服务了。然而,当我试图停止我的服务时,我会得到以下错误:Error 109: The pipe has been ended (但是它确实停止了服务)。

我主要是使用为windows-service提供的示例,但下面是相关代码(对于上下文和所有包装函数,请查看service.rs):

代码语言:javascript
复制
pub fn run_service() -> Result<()> {

    fn hi() -> impl actix_web::Responder {
        "Hello!\r\n"
    }

    let sys = actix_rt::System::new("test");

    actix_web::HttpServer::new(move || {
        actix_web::App::new()
            .route("/", actix_web::web::get().to(hi))
    })
    .bind("0.0.0.0:3000").unwrap()
    .start();

    let event_handler = move |control_event| -> ServiceControlHandlerResult {
        match control_event {
            ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
            ServiceControl::Stop => {
                actix_rt::System::with_current(|s| s.stop());
                ServiceControlHandlerResult::NoError
            }
            _ => ServiceControlHandlerResult::NotImplemented,
        }
    };

    let status_handle = service_control_handler::register(SERVICE_NAME, event_handler)?;

    status_handle.set_service_status(ServiceStatus {
        service_type: SERVICE_TYPE,
        current_state: ServiceState::Running,
        controls_accepted: ServiceControlAccept::STOP,
        exit_code: ServiceExitCode::Win32(0),
        checkpoint: 0,
        wait_hint: Duration::default(),
    })?;

    sys.run().unwrap();

    status_handle.set_service_status(ServiceStatus {
        service_type: SERVICE_TYPE,
        current_state: ServiceState::Stopped,
        controls_accepted: ServiceControlAccept::empty(),
        exit_code: ServiceExitCode::Win32(0),
        checkpoint: 0,
        wait_hint: Duration::default(),
    })?;

    Ok(())
}

如果我将System::stop放入thread::spawn中,则会得到一个不同的错误:The service did not return an error. This could be an internal Windows error or an internal service error。在这种情况下,它不会停止服务。

我已经输入了一些日志记录,看起来代码不可能通过sys.run().unwrap(),这是很奇怪的。

有什么想法吗?我以前从未使用过,所以我不知道自己在做什么。

编辑

我发现了主要的问题:在停止服务之前,我必须通知Windows服务已经停止。我用了一种笨重的方法让它发挥作用:

代码语言:javascript
复制
std::thread::spawn(move || {
    loop {
        if shutdown_signal.load(Ordering::Relaxed) {

            status_handle.set_service_status(ServiceStatus {
                service_type: SERVICE_TYPE,
                current_state: ServiceState::Stopped,
                controls_accepted: ServiceControlAccept::empty(),
                exit_code: ServiceExitCode::Win32(0),
                checkpoint: 0,
                wait_hint: Duration::default(),
            }).unwrap();

            actix_rt::System::current().stop();
            break;
        }
    }
});
sys.run().unwrap();
// ...

其中,shutdown_signal是我在事件处理程序中设置为true的AtomicBool。我要看看我是否可以通过actix_rt来代替。

EN

回答 1

Stack Overflow用户

发布于 2019-08-21 17:01:15

回答我自己的问题。我认为这是最好的方式来处理它,虽然我会很高兴看到其他解决方案!

代码语言:javascript
复制
pub fn run_service() -> Result<()> {

    use futures::Future;

    fn hi() -> impl actix_web::Responder {
        "Hello!\r\n"
    }

    let sys = actix_rt::System::new("test");

    actix_web::HttpServer::new(move || {
        actix_web::App::new()
            .route("/", actix_web::web::get().to(hi))
    })
    .bind("0.0.0.0:3000").unwrap()
    .start();

    let (mut send_stop, recv_stop) = {
        let (p, c) = futures::sync::oneshot::channel::<()>();
        (Some(p), c)
    };

    let event_handler = move |control_event| -> ServiceControlHandlerResult {
        match control_event {
            ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
            ServiceControl::Stop => {
                send_stop.take().unwrap().send(()).unwrap();
                ServiceControlHandlerResult::NoError
            }
            _ => ServiceControlHandlerResult::NotImplemented,
        }
    };

    let status_handle = service_control_handler::register(SERVICE_NAME, event_handler)?;

    status_handle.set_service_status(ServiceStatus {
        service_type: SERVICE_TYPE,
        current_state: ServiceState::Running,
        controls_accepted: ServiceControlAccept::STOP,
        exit_code: ServiceExitCode::Win32(0),
        checkpoint: 0,
        wait_hint: Duration::default(),
    })?;

    actix_rt::spawn(recv_stop.map(move |_| {
        status_handle.set_service_status(ServiceStatus {
            service_type: SERVICE_TYPE,
            current_state: ServiceState::Stopped,
            controls_accepted: ServiceControlAccept::empty(),
            exit_code: ServiceExitCode::Win32(0),
            checkpoint: 0,
            wait_hint: Duration::default(),
        }).unwrap();

        actix_rt::System::current().stop()
    }).map_err(|_| ()));

    sys.run().unwrap();

    Ok(())
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57583262

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档