I'm trying to use windows-service to run an actix web app. It provides a nice API and mostly works. I can start my service just fine. However, when I try to stop my service, I get the following error: Error 109: The pipe has been ended
(it does stop the service however).
I'm mostly just using the example provided for windows-service
, but here is the relevant code (for context and all the wrapper functions, check out 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(())
}
If I put the System::stop
in a thread::spawn
, I get a different error: The service did not return an error. This could be an internal Windows error or an internal service error
. In this case it does not stop the service.
I've put in some logging, and it doesn't look like the code ever gets past the sys.run().unwrap()
, which is strange.
Any thoughts? I've never used the Windows Service API before so I don't really know what I'm doing.
EDIT
I figured out what the main issue is: I have to notify Windows the service has stopped before stopping the service. I put together a clunky way to make it work:
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();
// ...
where shutdown_signal
is an AtomicBool
I set to true in the event handler. I'm going to see if I can do this instead somehow through actix_rt
.