Log when plugin runtime exits

This commit is contained in:
Gregory Schier
2024-07-25 09:28:08 -07:00
parent 80c1675331
commit d347f2db77
3 changed files with 37 additions and 20 deletions

View File

@@ -26,7 +26,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
.on_event(|app, e| match e { .on_event(|app, e| match e {
RunEvent::ExitRequested { code, .. } => { RunEvent::ExitRequested { code, .. } => {
tauri::async_runtime::block_on(async move { tauri::async_runtime::block_on(async move {
info!("Exiting plugin runtime because of app exit {:?}", code); info!("Exiting plugin runtime due to app exit {:?}", code);
let manager: State<Mutex<PluginManager>> = app.state(); let manager: State<Mutex<PluginManager>> = app.state();
manager.lock().await.cleanup(); manager.lock().await.cleanup();
}); });

View File

@@ -1,6 +1,6 @@
use command_group::GroupChild;
use log::{debug, info}; use log::{debug, info};
use tauri::{AppHandle, Manager, Runtime}; use tauri::{AppHandle, Manager, Runtime};
use tokio::sync::watch::Sender;
use tonic::transport::Channel; use tonic::transport::Channel;
use crate::nodejs::node_start; use crate::nodejs::node_start;
@@ -11,32 +11,27 @@ use crate::plugin_runtime::{
pub struct PluginManager { pub struct PluginManager {
client: PluginRuntimeClient<Channel>, client: PluginRuntimeClient<Channel>,
child: GroupChild, kill_tx: Sender<bool>,
} }
impl PluginManager { impl PluginManager {
pub async fn new<R: Runtime>(app_handle: &AppHandle<R>) -> PluginManager { pub async fn new<R: Runtime>(app_handle: &AppHandle<R>) -> PluginManager {
let temp_dir = app_handle.path().temp_dir().unwrap(); let temp_dir = app_handle.path().temp_dir().unwrap();
let start_resp = node_start(app_handle, &temp_dir).await; let (kill_tx, kill_rx) = tokio::sync::watch::channel(false);
let start_resp = node_start(app_handle, &temp_dir, &kill_rx).await;
info!("Connecting to gRPC client at {}", start_resp.addr); info!("Connecting to gRPC client at {}", start_resp.addr);
let client = match PluginRuntimeClient::connect(start_resp.addr.clone()).await { let client = match PluginRuntimeClient::connect(start_resp.addr.clone()).await {
Ok(v) => v, Ok(v) => v,
Err(err) => { Err(err) => panic!("{}", err.to_string()),
panic!("{}", err.to_string());
}
}; };
PluginManager { PluginManager { client, kill_tx }
client,
child: start_resp.child,
}
} }
pub fn cleanup(&mut self) { pub fn cleanup(&mut self) {
info!("Cleaning up NodeJS process"); self.kill_tx.send_replace(true);
self.child.kill().unwrap();
} }
pub async fn run_import(&mut self, data: &str) -> Result<HookResponse, String> { pub async fn run_import(&mut self, data: &str) -> Result<HookResponse, String> {

View File

@@ -2,8 +2,8 @@ use std::path::PathBuf;
use std::process::Command; use std::process::Command;
use std::time::Duration; use std::time::Duration;
use command_group::{CommandGroup, GroupChild}; use command_group::CommandGroup;
use log::{debug, info}; use log::{debug, error, info};
use rand::distributions::{Alphanumeric, DistString}; use rand::distributions::{Alphanumeric, DistString};
use serde; use serde;
use serde::Deserialize; use serde::Deserialize;
@@ -11,6 +11,7 @@ use tauri::path::BaseDirectory;
use tauri::{AppHandle, Manager, Runtime}; use tauri::{AppHandle, Manager, Runtime};
use tauri_plugin_shell::ShellExt; use tauri_plugin_shell::ShellExt;
use tokio::fs; use tokio::fs;
use tokio::sync::watch::Receiver;
#[derive(Deserialize, Default)] #[derive(Deserialize, Default)]
#[serde(default, rename_all = "camelCase")] #[serde(default, rename_all = "camelCase")]
@@ -20,10 +21,13 @@ struct PortFile {
pub struct StartResp { pub struct StartResp {
pub addr: String, pub addr: String,
pub child: GroupChild,
} }
pub async fn node_start<R: Runtime>(app: &AppHandle<R>, temp_dir: &PathBuf) -> StartResp { pub async fn node_start<R: Runtime>(
app: &AppHandle<R>,
temp_dir: &PathBuf,
kill_rx: &Receiver<bool>,
) -> StartResp {
let port_file_path = temp_dir.join(Alphanumeric.sample_string(&mut rand::thread_rng(), 10)); let port_file_path = temp_dir.join(Alphanumeric.sample_string(&mut rand::thread_rng(), 10));
let plugins_dir = app let plugins_dir = app
@@ -47,7 +51,7 @@ pub async fn node_start<R: Runtime>(app: &AppHandle<R>, temp_dir: &PathBuf) -> S
.to_string(); .to_string();
info!( info!(
"Starting plugin runtime\n port_file={}\n plugins_dir={}\n runtime_dir={}", "Starting plugin runtime\n port_file={}\n plugins_dir={}\n runtime_dir={}",
port_file_path.to_string_lossy(), port_file_path.to_string_lossy(),
plugins_dir, plugins_dir,
plugin_runtime_main, plugin_runtime_main,
@@ -61,10 +65,28 @@ pub async fn node_start<R: Runtime>(app: &AppHandle<R>, temp_dir: &PathBuf) -> S
.env("YAAK_PLUGINS_DIR", plugins_dir) .env("YAAK_PLUGINS_DIR", plugins_dir)
.args(&[plugin_runtime_main]); .args(&[plugin_runtime_main]);
let child = Command::from(cmd) println!("Waiting on plugin runtime");
let mut child = Command::from(cmd)
.group_spawn() .group_spawn()
.expect("yaaknode failed to start"); .expect("yaaknode failed to start");
let kill_rx = kill_rx.clone();
// Check on child
tokio::spawn(async move {
loop {
if let Ok(Some(status)) = child.try_wait() {
error!("Plugin runtime exited status={}", status);
// TODO: Try restarting plugin runtime
break;
} else if *kill_rx.borrow() {
info!("Stopping plugin runtime");
child.kill().expect("Failed to kill plugin runtime");
break;
}
}
});
let start = std::time::Instant::now(); let start = std::time::Instant::now();
let port_file_contents = loop { let port_file_contents = loop {
if start.elapsed().as_millis() > 30000 { if start.elapsed().as_millis() > 30000 {
@@ -84,5 +106,5 @@ pub async fn node_start<R: Runtime>(app: &AppHandle<R>, temp_dir: &PathBuf) -> S
info!("Started plugin runtime on :{}", port_file.port); info!("Started plugin runtime on :{}", port_file.port);
let addr = format!("http://localhost:{}", port_file.port); let addr = format!("http://localhost:{}", port_file.port);
StartResp { addr, child } StartResp { addr }
} }