【问题标题】:Problem running actix-web as Windows service将 actix-web 作为 Windows 服务运行时出现问题
【发布时间】:2022-03-08 01:33:33
【问题描述】:

我正在尝试使用 windows-service 来运行 actix 网络应用程序。它提供了一个很好的 API 并且大部分都可以工作。我可以开始我的服务就好了。但是,当我尝试停止服务时,我收到以下错误:Error 109: The pipe has been ended(但它确实停止了服务)。

我主要只是使用为windows-service 提供的示例,但这里是相关代码(对于上下文和所有包装函数,请查看https://github.com/mullvad/windows-service-rs/blob/master/examples/ping_service.rs):

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 服务 API,所以我真的不知道自己在做什么。

编辑

我弄清楚主要问题是什么:我必须在停止服务之前通知 Windows 服务已停止。我整理了一个笨拙的方法来使它工作:

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_signalAtomicBool 我在事件处理程序中设置为true。我将看看我是否可以通过actix_rt 以某种方式做到这一点。

【问题讨论】:

    标签: rust windows-services rust-actix actix-web


    【解决方案1】:

    回答我自己的问题。我认为这是处理它的最佳方法,尽管我很乐意看到其他解决方案!

    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(())
    }
    

    【讨论】:

      猜你喜欢
      • 2012-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-17
      • 1970-01-01
      • 1970-01-01
      • 2013-05-29
      • 1970-01-01
      相关资源
      最近更新 更多