基于 Prefect 的工作流引擎与前端(Vue3)的通信,仅通过API接口完全可实现前端按流程推进。以下是完整实现方案,包含技术选型、状态同步机制和代码示例:
一、通信架构设计
sequenceDiagram
participant Frontend as 前端(Vue3)
participant APIGateway as API网关
participant PrefectAPI as Prefect后端API
participant Database as 数据库
Frontend->>APIGateway: 发起流程启动请求
APIGateway->>PrefectAPI: 触发Prefect流定义
PrefectAPI->>Database: 记录流程实例状态
Database-->>PrefectAPI: 返回实例ID
PrefectAPI-->>APIGateway: 返回流程ID
APIGateway-->>Frontend: 响应流程ID
loop 状态轮询
Frontend->>PrefectAPI: 查询流程状态
PrefectAPI->>Database: 获取最新状态
Database-->>PrefectAPI: 返回JSON状态数据
PrefectAPI-->>Frontend: 返回状态+任务详情
Frontend->>Frontend: 动态渲染UI组件
end
opt 异常处理
Frontend->>PrefectAPI: 发送重试指令
PrefectAPI->>Prefect: 重新触发失败任务
end
二、核心实现步骤
1. 后端Prefect配置
# flows/production_flow.py
from prefect import Flow, task
from prefect.engine.signals import RETRY
import prefect
@task(max_retries=3, retry_delay=timedelta(seconds=10))
def critical_task():
if random.random() < 0.2:
raise RETRY("模拟随机失败")
return "success"
with Flow("production_flow") as flow:
result = critical_task()
# 部署到Prefect Server
flow.register(project_name="mes-system")
2. 前端通信接口设计
// src/api/prefect.ts
import axios from 'axios'
const PREFECT_API = process.env.VUE_APP_PREFECT_API
// 流程控制接口
export const startFlow = async (variables: object) => {
return axios.post(`${PREFECT_API}/flows/production_flow/run`, variables)
}
// 状态监控接口
export const pollFlowState = async (flowRunId: string) => {
return axios.get(`${PREFECT_API}/flow_runs/${flowRunId}`)
}
// 任务操作接口
export const retryTask = async (taskRunId: string) => {
return axios.post(`${PREFECT_API}/task_runs/${taskRunId}/retry`)
}
3. 前端状态管理(Vuex)
// src/store/prefect.js
const state = {
flowRun: null,
currentStep: 0,
tasks: []
}
const mutations = {
SET_FLOW_RUN(state, data) {
state.flowRun = data
state.currentStep = data.task_runs.findIndex(t => t.name === 'critical_task')
},
UPDATE_TASK_STATUS(state, { taskId, status }) {
const task = state.tasks.find(t => t.id === taskId)
if (task) task.status = status
}
}
const actions = {
async startProductionFlow({ commit }, params) {
const response = await startFlow(params)
commit('SET_FLOW_RUN', response.data)
commit('initPolling', response.data.id)
},
async pollFlowStatus({ commit, state }) {
const response = await pollFlowState(state.flowRun.id)
commit('UPDATE_FLOW_STATE', response.data)
// 检查是否需要更新任务列表
if (response.data.task_runs.some(t => !state.tasks.includes(t.id))) {
commit('SET_TASKS', response.data.task_runs)
}
}
}
三、前端流程推进实现
1. 动态路由控制
<!-- src/views/ProductionFlow.vue -->
<template>
<div>
<StepIndicator :current="currentStep" :total="5" />
<component :is="currentComponent" />
</div>
</template>
<script>
import { mapState } from 'vuex'
import StepIndicator from '@/components/StepIndicator.vue'
import DataEntry from '@/components/DataEntry.vue'
import ApprovalPanel from '@/components/ApprovalPanel.vue'
export default {
components: { StepIndicator, DataEntry, ApprovalPanel },
computed: {
...mapState(['currentStep'])
}
}
</script>
2. 实时状态更新
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
const app = createApp(App)
// 集成WebSocket实时更新
const ws = new WebSocket('wss://prefect.example.com/ws')
ws.onmessage = (event) => {
const data = JSON.parse(event.data)
if (data.type === 'prefect.state_update') {
store.dispatch('pollFlowStatus')
}
}
app.use(store)
app.mount('#app')
四、关键问题解决方案
1. 状态同步延迟问题
- 长轮询优化:设置15秒超时+指数退避重试
// src/utils/polling.js export const smartPoll = async (fn, interval = 15000) => { try { const result = await fn() return result } catch (err) { await new Promise(resolve => setTimeout(resolve, interval)) return smartPoll(fn, interval * 2) } }
2. 复杂流程可视化
- 使用D3.js渲染Prefect生成的DOT格式流程图
<!-- src/components/FlowVisualizer.vue --> <template> <svg ref="graph"></svg> </template> <script> import * as d3 from 'd3' export default { mounted() { d3.json('/prefect/flow/production_flow/dot').then(data => { const svg = d3.select(this.$refs.graph) // 渲染逻辑... }) } } </script>
3. 用户干预机制
// src/api/prefect.ts
// 手动干预接口
export const manualOverride = async (flowRunId: string, command: string) => {
return axios.post(`${PREFECT_API}/flow_runs/${flowRunId}/pause`, { command })
}
五、典型交互场景
前端操作 | 后端响应 | UI变化 |
---|---|---|
点击"启动生产" | 触发Prefect流执行 | 显示加载进度条 |
接收状态更新 | 任务状态变更 | 步骤指示器高亮当前任务 |
任务失败告警 | 推送错误消息到WebSocket | 弹出重试对话框 |
用户确认重试 | 调用prefect.retry_task API | 自动刷新任务状态 |
六、性能优化建议
-
缓存策略
- 使用Redis缓存频繁访问的流程定义(TTL=5分钟)
# prefect_backend/cache.py from redis import Redis cache = Redis(host='redis', port=6379) def get_flow_definition(flow_id): cached = cache.get(f"flow:{flow_id}") if not cached: cached = prefect.Flow.load(flow_id).to_dict() cache.setex(f"flow:{flow_id}", 300, cached) return cached
-
前端虚拟滚动
- 对长任务列表使用
vue-virtual-scroller
<template> <VirtualScroller :items="tasks" item-height="60"> <template #default="{ item }"> <TaskItem :task="item" /> </template> </VirtualScroller> </template>
- 对长任务列表使用
-
协议优化
- 使用Protocol Buffers替代JSON减少数据传输量
// prefect.proto message TaskState { string id = 1; enum Status { PENDING = 0; RUNNING = 1; FAILED = 2; SUCCESS = 3 } Status status = 2; string message = 3; }
七、架构演进建议
-
混合通信模式
- 常规状态查询使用HTTP API
- 实时事件推送使用WebSocket
- 文件传输使用gRPC-Web
-
前端微前端架构
graph LR A[主应用] --> B[流程设计器] A --> C[任务监控] A --> D[数据分析] B --> E[Prefect API] C --> E D --> E
结论:通过精心设计的API交互和前端状态管理,仅使用API接口即可实现与Prefect工作流的深度集成,且能实现流畅的流程引导体验。实际项目需重点关注状态同步延迟、错误恢复机制和接口性能优化。