1use std::sync::Arc;
5
6use chrono::Utc;
7use uuid::Uuid;
8
9use crate::error::{WorkflowError, WorkflowErrorCode, WorkflowResult};
10use crate::instance::{FlowInstance, InstanceStatus, PageRequest, PageResult, Task};
11use crate::integration::SensitiveFieldRegistry;
12use crate::observability::{AuditAction, AuditLogger, WorkflowEvent, WorkflowEventBus};
13use crate::repository::{DefinitionRepository, InstanceRepository};
14use crate::scheduling::candidate_resolver::CandidateResolver;
15
16use super::history::HistoryRecorder;
17use super::task_manager::TaskManager;
18
19#[derive(Debug, Clone, serde::Serialize)]
21pub struct InstanceSummary {
22 pub instance_id: String,
23 pub flow_key: String,
24 pub status: InstanceStatus,
25 pub current_nodes: Vec<String>,
26}
27
28#[derive(Debug, Clone, serde::Serialize)]
30pub struct InstanceDetail {
31 pub instance: FlowInstance,
32 pub current_tasks: Vec<Task>,
33}
34
35pub struct InstanceManager {
37 instance_repo: Arc<dyn InstanceRepository>,
38 definition_repo: Arc<dyn DefinitionRepository>,
39 task_manager: Arc<TaskManager>,
40 candidate_resolver: Arc<dyn CandidateResolver>,
41 history_recorder: Arc<HistoryRecorder>,
42 audit: Arc<AuditLogger>,
43 event_bus: Arc<dyn WorkflowEventBus>,
44 #[allow(dead_code)] sensitive_registry: Arc<SensitiveFieldRegistry>,
46}
47
48impl InstanceManager {
49 #[allow(clippy::too_many_arguments)]
50 pub fn new(
51 instance_repo: Arc<dyn InstanceRepository>,
52 definition_repo: Arc<dyn DefinitionRepository>,
53 task_manager: Arc<TaskManager>,
54 candidate_resolver: Arc<dyn CandidateResolver>,
55 history_recorder: Arc<HistoryRecorder>,
56 audit: Arc<AuditLogger>,
57 event_bus: Arc<dyn WorkflowEventBus>,
58 #[allow(dead_code)] sensitive_registry: Arc<SensitiveFieldRegistry>,
60 ) -> Self {
61 Self {
62 instance_repo,
63 definition_repo,
64 task_manager,
65 candidate_resolver,
66 history_recorder,
67 audit,
68 event_bus,
69 sensitive_registry,
70 }
71 }
72
73 pub async fn start(
75 &self,
76 flow_key: &str,
77 context: serde_json::Value,
78 initiator: &str,
79 ) -> WorkflowResult<InstanceSummary> {
80 let def = self
81 .definition_repo
82 .get_active(flow_key)
83 .await?
84 .ok_or_else(|| {
85 WorkflowError::with_field(
86 WorkflowErrorCode::DefinitionNotFound,
87 "流程定义不存在或无生效版本",
88 "flow_key",
89 flow_key,
90 )
91 })?;
92
93 let instance_id = Uuid::new_v4().to_string();
94 let instance = FlowInstance::new(
95 instance_id.clone(),
96 flow_key,
97 def.version.clone(),
98 initiator,
99 context,
100 &def.start_node,
101 );
102 self.instance_repo.create(&instance).await?;
103
104 self.history_recorder
105 .record_node_event(
106 &instance_id,
107 None,
108 &def.start_node,
109 crate::instance::HistoryEntryType::NodeEnter,
110 )
111 .await
112 .ok();
113
114 if let Some(start_node) = def.find_node(&def.start_node) {
115 if let crate::definition::NodeConfig::Start { next } = &start_node.config {
116 if let Some(next_node) = def.find_node(next) {
117 if let crate::definition::NodeConfig::Approval {
118 candidate_strategy, ..
119 } = &next_node.config
120 {
121 let candidates = self
122 .candidate_resolver
123 .resolve(candidate_strategy, &instance.context)
124 .await?;
125 self.task_manager
126 .create_tasks(&instance_id, next, candidates)
127 .await
128 .ok();
129 }
130 }
131 }
132 }
133
134 self.event_bus
135 .publish(WorkflowEvent::InstanceStarted {
136 instance_id: instance_id.clone(),
137 flow_key: flow_key.into(),
138 initiator: initiator.into(),
139 timestamp: Utc::now(),
140 })
141 .await
142 .ok();
143
144 self.audit.log_action(
145 AuditAction::Start,
146 initiator,
147 &instance_id,
148 InstanceStatus::Created,
149 InstanceStatus::Running,
150 serde_json::json!({"flow_key": flow_key}),
151 );
152
153 Ok(InstanceSummary {
154 instance_id,
155 flow_key: flow_key.into(),
156 status: InstanceStatus::Running,
157 current_nodes: instance.current_nodes.clone(),
158 })
159 }
160
161 pub async fn suspend(&self, instance_id: &str, actor: &str) -> WorkflowResult<()> {
163 let instance = self.load_instance(instance_id).await?;
164 if instance.status != InstanceStatus::Running {
165 return Err(WorkflowError::with_field(
166 WorkflowErrorCode::IllegalStatusTransition,
167 format!("非 running 状态不可挂起:{}", instance.status),
168 "status",
169 &instance.status.to_string(),
170 ));
171 }
172 let mut updated = instance.clone();
173 updated.status = InstanceStatus::Suspended;
174 updated.bump_version();
175 self.save_with_lock(&updated, instance.version_lock).await?;
176
177 self.event_bus
178 .publish(WorkflowEvent::InstanceSuspended {
179 instance_id: instance_id.into(),
180 actor: actor.into(),
181 timestamp: Utc::now(),
182 })
183 .await
184 .ok();
185 self.audit.log_action(
186 AuditAction::Suspend,
187 actor,
188 instance_id,
189 InstanceStatus::Running,
190 InstanceStatus::Suspended,
191 serde_json::json!({}),
192 );
193 Ok(())
194 }
195
196 pub async fn resume(&self, instance_id: &str, actor: &str) -> WorkflowResult<()> {
198 let instance = self.load_instance(instance_id).await?;
199 if instance.status != InstanceStatus::Suspended {
200 return Err(WorkflowError::with_field(
201 WorkflowErrorCode::IllegalStatusTransition,
202 format!("非 suspended 状态不可恢复:{}", instance.status),
203 "status",
204 &instance.status.to_string(),
205 ));
206 }
207 let mut updated = instance.clone();
208 updated.status = InstanceStatus::Running;
209 updated.bump_version();
210 self.save_with_lock(&updated, instance.version_lock).await?;
211
212 self.event_bus
213 .publish(WorkflowEvent::InstanceResumed {
214 instance_id: instance_id.into(),
215 actor: actor.into(),
216 timestamp: Utc::now(),
217 })
218 .await
219 .ok();
220 self.audit.log_action(
221 AuditAction::Resume,
222 actor,
223 instance_id,
224 InstanceStatus::Suspended,
225 InstanceStatus::Running,
226 serde_json::json!({}),
227 );
228 Ok(())
229 }
230
231 pub async fn terminate(&self, instance_id: &str, actor: &str) -> WorkflowResult<()> {
233 let instance = self.load_instance(instance_id).await?;
234 let mut updated = instance.clone();
235 updated.status = InstanceStatus::Terminated;
236 updated.bump_version();
237 self.save_with_lock(&updated, instance.version_lock).await?;
238 self.task_manager
239 .invalidate_by_instance(instance_id)
240 .await?;
241
242 self.event_bus
243 .publish(WorkflowEvent::InstanceTerminated {
244 instance_id: instance_id.into(),
245 actor: actor.into(),
246 timestamp: Utc::now(),
247 })
248 .await
249 .ok();
250 self.audit.log_action(
251 AuditAction::Terminate,
252 actor,
253 instance_id,
254 instance.status,
255 InstanceStatus::Terminated,
256 serde_json::json!({}),
257 );
258 Ok(())
259 }
260
261 pub async fn query(&self, instance_id: &str) -> WorkflowResult<InstanceDetail> {
263 let instance = self.load_instance(instance_id).await?;
264 let tasks = self.task_manager.list_by_instance(instance_id).await?;
265 Ok(InstanceDetail {
266 instance,
267 current_tasks: tasks,
268 })
269 }
270
271 pub async fn list_by_status(
273 &self,
274 status: InstanceStatus,
275 page: PageRequest,
276 ) -> WorkflowResult<PageResult<FlowInstance>> {
277 self.instance_repo.list_by_status(status, page).await
278 }
279
280 pub async fn query_history(
282 &self,
283 instance_id: &str,
284 ) -> WorkflowResult<Vec<crate::instance::HistoryEntry>> {
285 let entries = self
286 .history_recorder
287 .history_repo
288 .list_by_instance(instance_id)
289 .await?;
290 Ok(entries)
291 }
292
293 async fn load_instance(&self, instance_id: &str) -> WorkflowResult<FlowInstance> {
294 self.instance_repo.get(instance_id).await?.ok_or_else(|| {
295 WorkflowError::with_field(
296 WorkflowErrorCode::InstanceNotFound,
297 "实例不存在",
298 "instance_id",
299 instance_id,
300 )
301 })
302 }
303
304 async fn save_with_lock(&self, instance: &FlowInstance, expected: u64) -> WorkflowResult<()> {
305 let success = self
306 .instance_repo
307 .update_with_version(instance, expected)
308 .await?;
309 if !success {
310 return Err(WorkflowError::new(
311 WorkflowErrorCode::OptimisticLockConflict,
312 "乐观锁冲突",
313 ));
314 }
315 Ok(())
316 }
317}