feat(devops): 实现流水线状态实时推送功能

- 新增 WebSocket 实时推送流水线状态功能
- 优化流水线数据获取方式,改为实时推送
- 重构 WebSocket 相关代码,提高稳定性和可维护性
- 新增前端 WebSocket 客户端,用于接收实时推送数据
- 修改前端流水线页面,支持实时数据更新
This commit is contained in:
2025-07-23 23:09:59 +08:00
parent 902173a9e9
commit e23711e340
16 changed files with 224 additions and 106 deletions
@@ -23,3 +23,13 @@ export function queryLastPipelineDetail(instanceId) {
}
})
}
export function queryLastPipelineDetailWs(instanceId) {
return request({
url: 'api/devops/pipelineInstance/lastWs',
method: 'post',
data: {
instanceId
}
})
}
+12 -13
View File
@@ -1,25 +1,22 @@
import store from '@/store'
import Vue from 'vue'
/**
* WebSocket客户端
*/
export default function() {
const user = store.getters && store.getters.user
const webSocketApi = store.getters && store.getters.websocketApi
this.context = Vue.prototype
this.wsUri = webSocketApi.replace('{sid}', user.username)
function CsWsClient(sid) {
this.wsUri = store.getters && store.getters.websocketApi.replace('{sid}', sid)
this.client = null
/**
* 初始化WebSocket连接
* @param handleError -> function (e) { e是异常本身 }
* @param handleMessage -> function (e) { e.data是message }
*/
this.connect = function(handleError, handleMessage) {
this.wsClient = new WebSocket(this.wsUri)
this.client = new WebSocket(this.wsUri)
// 连接发生错误
this.wsClient.onerror = handleError
this.client.onerror = handleError
// 收到消息
this.wsClient.onmessage = handleMessage
this.client.onmessage = handleMessage
return this
}
/**
@@ -27,16 +24,18 @@ export default function() {
* @param data 客户端数据
*/
this.sendData = function(data) {
this.wsClient.send(JSON.stringify(data))
this.client.send(JSON.stringify(data))
}
/**
* 用于关闭ws连接
*/
this.close = function() {
console.log('关闭连接')
if (this.wsClient.readyState === 1) {
console.info('关闭连接')
if (this.client.readyState === 1) {
this.sendData([{}])
this.wsClient.close()
this.client.close()
}
}
}
export default CsWsClient
@@ -67,9 +67,10 @@
import CutePipelineNode from '@/views/components/dev/CutePipelineNode'
import { getPipelineTemplate } from '@/api/devops/pipelineTemplate'
import { queryLastPipelineDetail, restartPipeline, startPipeline } from '@/api/devops/pipelineInstance'
import { queryLastPipelineDetail, queryLastPipelineDetailWs, startPipeline } from '@/api/devops/pipelineInstance'
import { CountArraysObjectByPropKey, FormatDateTimeStr } from '@/utils/CsUtil'
import CsMessage from '@/utils/elementui/CsMessage'
import CsWsClient from '@/utils/CsWsClient'
export default {
name: 'CutePipelineNodeDemo',
@@ -458,16 +459,18 @@ export default {
dynamicStartButtonLoading: false,
dynamicTemplate: [],
dynamicHook: null,
dynamicInstance: {}
dynamicInstance: {},
dynamicWsClient: null
}
},
mounted() {
this.refreshData()
this.initPipelineTemplate(4)
const pipelineInstanceId = sessionStorage.getItem('pipelineInstanceId')
if (pipelineInstanceId) {
this.fetchLastDetail(pipelineInstanceId)
}
// const pipelineInstanceId = sessionStorage.getItem('pipelineInstanceId')
// if (pipelineInstanceId) {
// this.fetchLastDetail(pipelineInstanceId)
// }
// this.connectWebSocketServer(pipelineInstanceId)
},
methods: {
refreshData() {
@@ -486,6 +489,11 @@ export default {
}
this.dataList3 = [...this.dataList3]
},
/**
* 初始化流水线模板
* @param templateId
* @returns {Promise<void>}
*/
async initPipelineTemplate(templateId) {
const pipelineTemplate = await getPipelineTemplate(templateId)
if (pipelineTemplate && pipelineTemplate.template) {
@@ -496,6 +504,51 @@ export default {
}
}
},
/**
* 连接WebSocket服务
*/
connectWebSocketServer(instanceId) {
const that = this
const sid = 'instanceId_' + instanceId
that.dynamicWsClient = new CsWsClient(sid)
that.dynamicWsClient.connect(that.handleWebSocketError, that.handleWebSocketMessage)
setTimeout(() => {
// 请求推送流水线数据
queryLastPipelineDetailWs(sid)
that.dynamicStartButtonLoading = false
that.dynamicStartupStatus = that.dynamicStartupStatusMap.restart.code
}, 1000)
},
handleWebSocketError(e) {
console.error('连接WebSocket服务失败', e)
},
handleWebSocketMessage(e) {
const that = this
const data = e.data
// console.error('来自服务器的数据:data', data)
const callbackData = JSON.parse(data)
// console.error('callbackData', callbackData)
try {
that.dynamicInstance = JSON.parse(callbackData.data)
// 判断流水线是否结束
const successCount = CountArraysObjectByPropKey(that.dynamicInstance.nodes, 'status', 'success')
if (that.dynamicTemplate && that.dynamicTemplate.length === successCount) {
if (that.dynamicWsClient) {
that.dynamicWsClient.close()
}
that.dynamicStartupStatus = that.dynamicStartupStatusMap.start.code
} else {
that.dynamicStartupStatus = that.dynamicStartupStatusMap.restart.code
}
} catch (e) {
// ignore
}
},
/**
* 通过Http的方式拉取流水线最新的状态
* @param instanceId
* @returns {Promise<void>}
*/
async fetchLastDetail(instanceId) {
const that = this
const intervalTime = 2000
@@ -517,6 +570,10 @@ export default {
that.dynamicStartButtonLoading = false
}, 2000)
},
/**
* 启动流水线
* @returns {Promise<void>}
*/
async startPipelineTest() {
const that = this
try {
@@ -535,8 +592,9 @@ export default {
// }
const result = await startPipeline()
CsMessage.Success('流水线启动成功')
await that.fetchLastDetail(result.instanceId)
// await that.fetchLastDetail(result.instanceId)
sessionStorage.setItem('pipelineInstanceId', result.instanceId)
this.connectWebSocketServer(result.instanceId)
} catch (e) {
that.dynamicStartButtonLoading = false
}