sz_rust_workflow/integration/
plugin_unload_watcher.rs1use std::sync::Arc;
5
6use crate::error::WorkflowResult;
7use crate::repository::InstanceRepository;
8
9pub struct PluginUnloadWatcher {
14 instance_repo: Arc<dyn InstanceRepository>,
15}
16
17impl PluginUnloadWatcher {
18 pub fn new(instance_repo: Arc<dyn InstanceRepository>) -> Self {
19 Self { instance_repo }
20 }
21
22 pub async fn on_plugin_unload(&self, plugin_name: &str) -> WorkflowResult<()> {
26 let instances = self.instance_repo.list_running().await?;
27 for mut inst in instances {
28 let mut changed = false;
29 if let serde_json::Value::Object(ref mut obj) = inst.context {
30 if let Some(unavailable) = obj
31 .get_mut("_unavailable_plugins")
32 .and_then(|v| v.as_array_mut())
33 {
34 unavailable.push(serde_json::Value::String(plugin_name.to_string()));
35 changed = true;
36 } else {
37 obj.insert(
38 "_unavailable_plugins".into(),
39 serde_json::json!([plugin_name]),
40 );
41 changed = true;
42 }
43 }
44 if changed {
45 let expected = inst.version_lock;
46 let _ = self
47 .instance_repo
48 .update_with_version(&inst, expected)
49 .await?;
50 }
51 }
52 Ok(())
53 }
54
55 pub fn is_plugin_unavailable(
57 instance: &crate::instance::FlowInstance,
58 plugin_name: &str,
59 ) -> bool {
60 instance
61 .context
62 .get("_unavailable_plugins")
63 .and_then(|v| v.as_array())
64 .map(|arr| arr.iter().any(|v| v.as_str() == Some(plugin_name)))
65 .unwrap_or(false)
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72 use crate::repository::InMemoryInstanceRepository;
73
74 #[tokio::test]
75 async fn on_plugin_unload_marks_instances() {
76 let repo = Arc::new(InMemoryInstanceRepository::default());
77 let inst = crate::instance::FlowInstance::new(
78 "i1",
79 "test",
80 semver::Version::new(1, 0, 0),
81 "u1",
82 serde_json::json!({}),
83 "start",
84 );
85 repo.create(&inst).await.unwrap();
86
87 let watcher = PluginUnloadWatcher::new(repo.clone());
88 watcher.on_plugin_unload("crm").await.unwrap();
89
90 let got = repo.get("i1").await.unwrap().unwrap();
91 assert!(PluginUnloadWatcher::is_plugin_unavailable(&got, "crm"));
92 assert!(!PluginUnloadWatcher::is_plugin_unavailable(&got, "erp"));
93 }
94
95 #[tokio::test]
96 async fn no_running_instances() {
97 let repo = Arc::new(InMemoryInstanceRepository::default());
98 let watcher = PluginUnloadWatcher::new(repo);
99 watcher.on_plugin_unload("crm").await.unwrap();
100 }
101}