修复了 Python 插件停不下来就真的停不下来的问题

This commit is contained in:
shenjack-5600u 2025-04-07 05:28:29 +08:00
parent 3ce0e0004d
commit 5d93e38237
Signed by: shenjack
GPG Key ID: FDF9864E11C7E79F
4 changed files with 33 additions and 12 deletions

View File

@ -33,6 +33,8 @@ pub enum PyPluginError {
/// 插件内函数调用错误 /// 插件内函数调用错误
/// pyerr, func_name, module_name /// pyerr, func_name, module_name
FuncCallError(pyo3::PyErr, String, String), FuncCallError(pyo3::PyErr, String, String),
/// 插件停不下来!
PluginNotStopped,
} }
impl From<rust_socketio::Error> for IcaError { impl From<rust_socketio::Error> for IcaError {
@ -80,6 +82,9 @@ impl std::fmt::Display for PyPluginError {
} }
PyPluginError::FuncCallError(py_err, name, module) => { PyPluginError::FuncCallError(py_err, name, module) => {
write!(f, "插件内函数调用错误: {:#?}|{} in {}", py_err, name, module) write!(f, "插件内函数调用错误: {:#?}|{} in {}", py_err, name, module)
},
PyPluginError::PluginNotStopped => {
write!(f, "插件未停止")
} }
} }
} }
@ -111,6 +116,7 @@ impl std::error::Error for PyPluginError {
PyPluginError::CouldNotGetFunc(e, _, _) => Some(e), PyPluginError::CouldNotGetFunc(e, _, _) => Some(e),
PyPluginError::FuncNotCallable(_, _) => None, PyPluginError::FuncNotCallable(_, _) => None,
PyPluginError::FuncCallError(e, _, _) => Some(e), PyPluginError::FuncCallError(e, _, _) => Some(e),
PyPluginError::PluginNotStopped => None,
} }
} }
} }

View File

@ -17,6 +17,7 @@ mod ica;
mod tailchat; mod tailchat;
use config::BotConfig; use config::BotConfig;
use error::PyPluginError;
use tracing::{event, span, Level}; use tracing::{event, span, Level};
pub static mut MAIN_STATUS: status::BotStatus = status::BotStatus { pub static mut MAIN_STATUS: status::BotStatus = status::BotStatus {
@ -139,15 +140,30 @@ fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt().with_max_level(level).init(); tracing_subscriber::fmt().with_max_level(level).init();
let _ = tokio::runtime::Builder::new_multi_thread() let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all() .enable_all()
.thread_name("shenbot-rs") .thread_name("shenbot-rs")
.worker_threads(10) .worker_threads(10)
.build() .build()
.unwrap() .unwrap();
let result = rt
.block_on(inner_main()); .block_on(inner_main());
event!(Level::INFO, "shenbot-rs v{} exiting", VERSION); event!(Level::INFO, "shenbot-rs v{} exiting", VERSION);
match result {
Ok(_) => {}
Err(e) => {
if let Some(PyPluginError::PluginNotStopped) = e.downcast_ref::<PyPluginError>() {
event!(Level::WARN, "Python 插件停不下来, 3s 后终止 tokio rt");
rt.shutdown_timeout(Duration::from_secs(3));
} else {
event!(Level::ERROR, "shenbot-rs v{} exiting with error: {}", VERSION, e);
}
}
}
Ok(()) Ok(())
} }

View File

@ -15,6 +15,7 @@ use pyo3::types::PyTuple;
use pyo3::{intern, prelude::*}; use pyo3::{intern, prelude::*};
use tracing::{event, span, warn, Level}; use tracing::{event, span, warn, Level};
use crate::error::PyPluginError;
use crate::MainStatus; use crate::MainStatus;
const REQUIRE_CONFIG_FUNC_NAME: &str = "require_config"; const REQUIRE_CONFIG_FUNC_NAME: &str = "require_config";
@ -575,18 +576,13 @@ pub async fn post_py() -> anyhow::Result<()> {
status.config.sync_status_to_config(); status.config.sync_status_to_config();
status.config.write_to_default()?; status.config.write_to_default()?;
stop_tasks().await; stop_tasks().await?;
unsafe {
if !pyo3::ffi::Py_FinalizeEx() == 0 {
event!(Level::ERROR, "Python 退出失败 (不过应该无所谓)");
}
}
Ok(()) Ok(())
} }
async fn stop_tasks() { async fn stop_tasks() -> Result<(), PyPluginError> {
if call::PY_TASKS.lock().await.is_empty() { if call::PY_TASKS.lock().await.is_empty() {
return; return Ok(());
} }
let waiter = tokio::spawn(async { let waiter = tokio::spawn(async {
call::PY_TASKS.lock().await.join_all().await; call::PY_TASKS.lock().await.join_all().await;
@ -594,10 +590,11 @@ async fn stop_tasks() {
tokio::select! { tokio::select! {
_ = waiter => { _ = waiter => {
event!(Level::INFO, "Python 任务完成"); event!(Level::INFO, "Python 任务完成");
Ok(())
} }
_ = tokio::signal::ctrl_c() => { _ = tokio::signal::ctrl_c() => {
call::PY_TASKS.lock().await.cancel_all(); event!(Level::WARN, "正在强制结束 Python 任务");
event!(Level::INFO, "Python 任务被中断"); Err(PyPluginError::PluginNotStopped)
} }
} }
} }

View File

@ -2,6 +2,8 @@
## 0.9.0 ## 0.9.0
- 修复了 Python 插件停不下来就真的停不下来的问题
### ica 2.0.1 ### ica 2.0.1
> 添加了 `Room` 相关的 api > 添加了 `Room` 相关的 api