feat(devops): 实现流水线节点执行功能
- 新增 PipelineJobBean 类作为流水线任务载体 - 重构 PipelineJobManage 类,支持节点级任务管理 - 新增 PipelineNodeJobManage 类用于管理节点任务 - 实现节点任务的启动、中断和删除功能 - 新增节点日志切面和切面类
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function startPipeline() {
|
||||||
|
return request({
|
||||||
|
url: 'api/devops/pipeline/start',
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function restartPipeline() {
|
||||||
|
return request({
|
||||||
|
url: 'api/devops/pipeline/restart',
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryLastPipelineDetail(instanceId) {
|
||||||
|
return request({
|
||||||
|
url: 'api/devops/pipeline/last',
|
||||||
|
method: 'post',
|
||||||
|
data: {
|
||||||
|
instanceId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -75,6 +75,19 @@ const LabelUtil = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SizeUtil = {
|
||||||
|
formatBytes: function(value) {
|
||||||
|
if (typeof value !== 'number' || isNaN(value) || value <= 0) {
|
||||||
|
return '0 Bytes'
|
||||||
|
}
|
||||||
|
const units = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
||||||
|
const index = Math.floor(Math.log(value) / Math.log(1024))
|
||||||
|
const unit = units[Math.min(index, units.length - 1)]
|
||||||
|
const result = (value / Math.pow(1024, index)).toFixed(2)
|
||||||
|
return `${result} ${unit}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const DateUtil = {
|
const DateUtil = {
|
||||||
formatDate: function(originVal) {
|
formatDate: function(originVal) {
|
||||||
if (originVal === undefined) {
|
if (originVal === undefined) {
|
||||||
@@ -119,5 +132,6 @@ export {
|
|||||||
StringUtil,
|
StringUtil,
|
||||||
ObjectUtil,
|
ObjectUtil,
|
||||||
LabelUtil,
|
LabelUtil,
|
||||||
DateUtil
|
DateUtil,
|
||||||
|
SizeUtil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,13 @@
|
|||||||
:style="{
|
:style="{
|
||||||
borderTopWidth: '5px',
|
borderTopWidth: '5px',
|
||||||
borderTopStyle: 'solid',
|
borderTopStyle: 'solid',
|
||||||
borderTopColor: statusColorConst[templateData.status].color
|
borderTopColor: statusColorConst[pipelineData.currentNodeStatus ? pipelineData.currentNodeStatus : statusColorConst.pending.code].color
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<div style="float: left;">
|
<div style="float: left;">
|
||||||
<i
|
<i
|
||||||
v-if="templateData.currentNodeStatus === 'pending'"
|
v-if="pipelineData.currentNodeStatus && pipelineData.currentNodeStatus === statusColorConst.pending.code"
|
||||||
class="el-icon-time"
|
class="el-icon-time"
|
||||||
:style="{
|
:style="{
|
||||||
fontSize: '22px',
|
fontSize: '22px',
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
<i
|
<i
|
||||||
v-else-if="templateData.currentNodeStatus === 'running'"
|
v-else-if="pipelineData.currentNodeStatus && pipelineData.currentNodeStatus === statusColorConst.running.code"
|
||||||
class="el-icon-loading"
|
class="el-icon-loading"
|
||||||
:style="{
|
:style="{
|
||||||
fontSize: '22px',
|
fontSize: '22px',
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
<i
|
<i
|
||||||
v-else-if="templateData.currentNodeStatus === 'success'"
|
v-else-if="pipelineData.currentNodeStatus && pipelineData.currentNodeStatus === statusColorConst.success.code"
|
||||||
class="el-icon-success"
|
class="el-icon-success"
|
||||||
:style="{
|
:style="{
|
||||||
fontSize: '22px',
|
fontSize: '22px',
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
<i
|
<i
|
||||||
v-else-if="templateData.currentNodeStatus === 'fail'"
|
v-else-if="pipelineData.currentNodeStatus && pipelineData.currentNodeStatus === statusColorConst.fail.code"
|
||||||
class="el-icon-error"
|
class="el-icon-error"
|
||||||
:style="{
|
:style="{
|
||||||
fontSize: '22px',
|
fontSize: '22px',
|
||||||
@@ -43,25 +43,25 @@
|
|||||||
/>
|
/>
|
||||||
<i
|
<i
|
||||||
v-else
|
v-else
|
||||||
class="el-icon-error"
|
class="el-icon-time"
|
||||||
:style="{
|
:style="{
|
||||||
fontSize: '22px',
|
fontSize: '22px',
|
||||||
color: statusColorConst.fail.color
|
color: statusColorConst.pending.color
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-name">{{ templateData.name }}</div>
|
<div class="box-name">{{ pipelineData.name }}</div>
|
||||||
<div style="clear: both" />
|
<div style="clear: both" />
|
||||||
</div>
|
</div>
|
||||||
<div class="box-current-node">
|
<div class="box-current-node">
|
||||||
<a @click="onCurrentNodeClick">
|
<a @click="onCurrentNodeClick">
|
||||||
{{ templateData.currentNodeMsg }}
|
{{ pipelineData.currentNodeMsg ? pipelineData.currentNodeMsg : statusColorConst.pending.label }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12" style="text-align: left">
|
<el-col :span="12" style="text-align: left">
|
||||||
<!-- 流水线状态为fail,且节点支持重试 -->
|
<!-- 流水线状态为fail,且节点支持重试 -->
|
||||||
<div v-if="templateData.status === 'fail' && templateData.retry === true">
|
<div v-if="pipelineData.currentNodeStatus === 'fail' && pipelineData.retry === true">
|
||||||
<div class="box-buttons">
|
<div class="box-buttons">
|
||||||
<el-button
|
<el-button
|
||||||
type="text"
|
type="text"
|
||||||
@@ -77,30 +77,13 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 流水线状态为running,且有操作按钮 -->
|
|
||||||
<div v-else-if="templateData.status === 'running' && templateData.buttons && templateData.buttons.length > 0">
|
|
||||||
<div class="box-buttons">
|
|
||||||
<el-button
|
|
||||||
v-for="buttonItem in templateData.buttons"
|
|
||||||
:key="buttonItem.service"
|
|
||||||
size="medium"
|
|
||||||
type="text"
|
|
||||||
:style="{
|
|
||||||
padding: 0,
|
|
||||||
margin: '0 10px 0 10px',
|
|
||||||
color: ['apply','agree','ok','success'].includes(buttonItem.code) ? 'green' : 'red'
|
|
||||||
}"
|
|
||||||
@click="onNodeOperationClick(buttonItem)"
|
|
||||||
>
|
|
||||||
{{ buttonItem.title }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- 流水线状态为success,且有需要满足条件的操作按钮 -->
|
<!-- 流水线状态为success,且有需要满足条件的操作按钮 -->
|
||||||
<div v-else-if="templateData.status === 'success' && templateData.buttons && templateData.buttons.length > 0">
|
<div
|
||||||
|
v-else-if="pipelineData.currentNodeStatus === statusColorConst.success.code && pipelineData.buttons && pipelineData.buttons.length > 0"
|
||||||
|
>
|
||||||
<div class="box-buttons">
|
<div class="box-buttons">
|
||||||
<el-button
|
<el-button
|
||||||
v-for="buttonItem in templateData.buttons"
|
v-for="buttonItem in pipelineData.buttons"
|
||||||
:key="buttonItem.service"
|
:key="buttonItem.service"
|
||||||
size="medium"
|
size="medium"
|
||||||
type="text"
|
type="text"
|
||||||
@@ -108,7 +91,28 @@
|
|||||||
padding: 0,
|
padding: 0,
|
||||||
margin: '0 10px 0 10px',
|
margin: '0 10px 0 10px',
|
||||||
color: ['apply','agree','ok','success'].includes(buttonItem.code) ? 'green' : 'red',
|
color: ['apply','agree','ok','success'].includes(buttonItem.code) ? 'green' : 'red',
|
||||||
display: ['success', 'fail'].includes(buttonItem.code) && templateData.status === buttonItem.code ? '' : 'none'
|
display: ['success', 'fail'].includes(buttonItem.code) && pipelineData.status === buttonItem.code ? '' : 'none'
|
||||||
|
}"
|
||||||
|
@click="onNodeOperationClick(buttonItem)"
|
||||||
|
>
|
||||||
|
{{ buttonItem.title }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 流水线状态非pending,且有操作按钮 -->
|
||||||
|
<div
|
||||||
|
v-else-if="pipelineData.currentNodeStatus !== statusColorConst.pending.code && pipelineData.buttons && pipelineData.buttons.length > 0"
|
||||||
|
>
|
||||||
|
<div class="box-buttons">
|
||||||
|
<el-button
|
||||||
|
v-for="buttonItem in pipelineData.buttons"
|
||||||
|
:key="buttonItem.service"
|
||||||
|
size="medium"
|
||||||
|
type="text"
|
||||||
|
:style="{
|
||||||
|
padding: 0,
|
||||||
|
margin: '0 10px 0 10px',
|
||||||
|
color: ['apply','agree','ok','success'].includes(buttonItem.code) ? 'green' : 'red'
|
||||||
}"
|
}"
|
||||||
@click="onNodeOperationClick(buttonItem)"
|
@click="onNodeOperationClick(buttonItem)"
|
||||||
>
|
>
|
||||||
@@ -128,7 +132,7 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<div style="clear: both" />
|
<div style="clear: both" />
|
||||||
</el-row>
|
</el-row>
|
||||||
<cute-preview-drawer ref="detailDrawer" :title="templateData.name">
|
<cute-preview-drawer ref="detailDrawer" :title="pipelineData.name">
|
||||||
<div style="padding: 20px">
|
<div style="padding: 20px">
|
||||||
这里是明细
|
这里是明细
|
||||||
</div>
|
</div>
|
||||||
@@ -155,28 +159,26 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
statusColorConst: {
|
statusColorConst: {
|
||||||
pending: { label: '未开始', color: '#C0C4CC' },
|
pending: { code: 'pending', label: '未开始', color: '#C0C4CC' },
|
||||||
running: { label: '运行中', color: '#67C23A' },
|
running: { code: 'running', label: '运行中', color: '#67C23A' },
|
||||||
success: { label: '执行成功', color: '#67C23A' },
|
success: { code: 'success', label: '执行成功', color: '#67C23A' },
|
||||||
fail: { label: '执行失败', color: '#F56C6C' }
|
fail: { code: 'fail', label: '执行失败', color: '#F56C6C' }
|
||||||
},
|
},
|
||||||
executeTimeStr: ''
|
executeTimeStr: '',
|
||||||
|
pipelineData: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
templateData: {
|
templateData: {
|
||||||
handler(newVal, oldVal) {
|
handler(newVal, oldVal) {
|
||||||
|
this.pipelineData = { ...newVal }
|
||||||
this.executeTimeStr = this.renderDateTimeStr(newVal)
|
this.executeTimeStr = this.renderDateTimeStr(newVal)
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// computed: {
|
|
||||||
// formatExecuteTimeStr() {
|
|
||||||
// return this.renderDateTimeStr(this.templateData)
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.pipelineData = this.templateData
|
||||||
this.executeTimeStr = this.renderDateTimeStr(this.templateData)
|
this.executeTimeStr = this.renderDateTimeStr(this.templateData)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -189,7 +191,20 @@ export default {
|
|||||||
case 'running':
|
case 'running':
|
||||||
case 'success':
|
case 'success':
|
||||||
case 'fail':
|
case 'fail':
|
||||||
executeTimeStr = this.formatTimeDifference(newVal.startTime, newVal.updateTime)
|
if (newVal.currentNodeStatus !== this.statusColorConst.pending.code) {
|
||||||
|
if (newVal.startTime && newVal.finishTime) {
|
||||||
|
executeTimeStr = this.formatTimeDifference(newVal.startTime, newVal.finishTime)
|
||||||
|
return executeTimeStr
|
||||||
|
}
|
||||||
|
if (newVal.startTime) {
|
||||||
|
executeTimeStr = this.formatTimeDifference(newVal.startTime, new Date())
|
||||||
|
return executeTimeStr
|
||||||
|
}
|
||||||
|
if (newVal.createTime) {
|
||||||
|
executeTimeStr = this.formatTimeDifference(newVal.createTime, new Date())
|
||||||
|
return executeTimeStr
|
||||||
|
}
|
||||||
|
}
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
executeTimeStr = ''
|
executeTimeStr = ''
|
||||||
@@ -223,10 +238,11 @@ export default {
|
|||||||
if (seconds >= 0) {
|
if (seconds >= 0) {
|
||||||
return `${seconds} 秒`
|
return `${seconds} 秒`
|
||||||
}
|
}
|
||||||
|
return `${diffInMilliseconds} 毫秒`
|
||||||
},
|
},
|
||||||
onCurrentNodeClick() {
|
onCurrentNodeClick() {
|
||||||
const templateData = this.templateData || { click: false }
|
const pipelineData = this.pipelineData || { click: false }
|
||||||
if (!templateData.click) {
|
if (!pipelineData.click) {
|
||||||
console.warn('当前流水线节点不支持查看明细')
|
console.warn('当前流水线节点不支持查看明细')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -234,12 +250,12 @@ export default {
|
|||||||
this.$refs.detailDrawer.show()
|
this.$refs.detailDrawer.show()
|
||||||
},
|
},
|
||||||
onNodeRetryClick() {
|
onNodeRetryClick() {
|
||||||
const templateData = this.templateData || { retry: false }
|
const pipelineData = this.pipelineData || { retry: false }
|
||||||
if (!templateData.retry) {
|
if (!pipelineData.retry) {
|
||||||
console.warn('当前流水线节点不支持重试')
|
console.warn('当前流水线节点不支持重试')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
console.error('templateData', this.templateData)
|
console.error('pipelineData', this.pipelineData)
|
||||||
},
|
},
|
||||||
onNodeOperationClick(buttonInfo) {
|
onNodeOperationClick(buttonInfo) {
|
||||||
console.error('buttonInfo', buttonInfo)
|
console.error('buttonInfo', buttonInfo)
|
||||||
@@ -277,7 +293,7 @@ export default {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
text-wrap: nowrap;
|
text-wrap: nowrap;
|
||||||
font-size: 18px;
|
font-size: 15px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-divider>演示:运行中</el-divider>
|
<el-divider>演示:动态流水线 <el-button type="primary" @click="startPipelineTest">启动流水线</el-button></el-divider>
|
||||||
<div class="box-pipeline">
|
<div class="box-pipeline">
|
||||||
<div v-if="dataList1 && dataList1.length > 0" class="box-pipeline-content">
|
<div v-if="dynamicList && dynamicList.length > 0" class="box-pipeline-content">
|
||||||
<cute-pipeline-node
|
<cute-pipeline-node
|
||||||
v-for="(template, index) in dataList1"
|
v-for="(template, index) in dynamicList"
|
||||||
:key="template.code"
|
:key="template.code"
|
||||||
:template-data="dataList1[index]"
|
:template-data.sync="dynamicList[index]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="box-pipeline-content">
|
<div v-else class="box-pipeline-content">
|
||||||
<cute-pipeline-node
|
<cute-pipeline-node
|
||||||
v-for="(template, index) in templateList"
|
v-for="(template, index) in templateList"
|
||||||
:key="template.code"
|
:key="template.code"
|
||||||
:template-data="dataList1[index]"
|
:template-data.sync="templateList[index]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -23,14 +23,14 @@
|
|||||||
<cute-pipeline-node
|
<cute-pipeline-node
|
||||||
v-for="(template, index) in dataList2"
|
v-for="(template, index) in dataList2"
|
||||||
:key="template.code"
|
:key="template.code"
|
||||||
:template-data="dataList2[index]"
|
:template-data.sync="dataList2[index]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="box-pipeline-content">
|
<div v-else class="box-pipeline-content">
|
||||||
<cute-pipeline-node
|
<cute-pipeline-node
|
||||||
v-for="(template, index) in templateList"
|
v-for="(template, index) in templateList"
|
||||||
:key="template.code"
|
:key="template.code"
|
||||||
:template-data="dataList2[index]"
|
:template-data.sync="templateList[index]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -40,14 +40,14 @@
|
|||||||
<cute-pipeline-node
|
<cute-pipeline-node
|
||||||
v-for="(template, index) in dataList3"
|
v-for="(template, index) in dataList3"
|
||||||
:key="template.code"
|
:key="template.code"
|
||||||
:template-data="dataList3[index]"
|
:template-data.sync="dataList3[index]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="box-pipeline-content">
|
<div v-else class="box-pipeline-content">
|
||||||
<cute-pipeline-node
|
<cute-pipeline-node
|
||||||
v-for="(template, index) in templateList"
|
v-for="(template, index) in templateList"
|
||||||
:key="template.code"
|
:key="template.code"
|
||||||
:template-data="dataList3[index]"
|
:template-data.sync="templateList[index]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -58,6 +58,7 @@
|
|||||||
|
|
||||||
import CutePipelineNode from '@/views/components/dev/CutePipelineNode'
|
import CutePipelineNode from '@/views/components/dev/CutePipelineNode'
|
||||||
import { formatDateTimeStr } from '@/utils'
|
import { formatDateTimeStr } from '@/utils'
|
||||||
|
import { startPipeline, queryLastPipelineDetail } from '@/api/devops/pipeline'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CutePipelineNodeDemo',
|
name: 'CutePipelineNodeDemo',
|
||||||
@@ -154,147 +155,6 @@ export default {
|
|||||||
click: false,
|
click: false,
|
||||||
retry: true
|
retry: true
|
||||||
}],
|
}],
|
||||||
// 运行中
|
|
||||||
dataList1: [
|
|
||||||
{
|
|
||||||
code: 'node_init',
|
|
||||||
type: 'service',
|
|
||||||
name: '初始化',
|
|
||||||
createTime: '2025-07-17 21:12:01',
|
|
||||||
updateTime: '2025-07-17 21:13:01',
|
|
||||||
startTime: '2025-07-17 21:13:01',
|
|
||||||
currentNodeMsg: '执行成功',
|
|
||||||
currentNodeStatus: 'success',
|
|
||||||
status: 'success'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 'node_merge_branch',
|
|
||||||
type: 'service',
|
|
||||||
name: '合并代码',
|
|
||||||
click: true,
|
|
||||||
retry: true,
|
|
||||||
createTime: '2025-07-17 21:13:01',
|
|
||||||
updateTime: '2025-07-17 21:18:01',
|
|
||||||
startTime: '2025-07-17 21:13:01',
|
|
||||||
currentNodeMsg: '执行成功',
|
|
||||||
currentNodeStatus: 'success',
|
|
||||||
status: 'success'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 'node_build_java',
|
|
||||||
type: 'service',
|
|
||||||
name: '构建',
|
|
||||||
click: true,
|
|
||||||
retry: true,
|
|
||||||
detailType: 'gitlab',
|
|
||||||
parameters: {
|
|
||||||
pipeline: 'pipeline-backend'
|
|
||||||
},
|
|
||||||
createTime: '2025-07-17 21:18:01',
|
|
||||||
updateTime: '2025-07-17 21:28:01',
|
|
||||||
startTime: '2025-07-17 21:18:01',
|
|
||||||
currentNodeMsg: '执行成功',
|
|
||||||
currentNodeStatus: 'success',
|
|
||||||
status: 'success'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 'node_image_scan',
|
|
||||||
type: 'service',
|
|
||||||
name: '镜像扫描',
|
|
||||||
click: true,
|
|
||||||
retry: true,
|
|
||||||
detailType: 'gitlab',
|
|
||||||
parameters: {
|
|
||||||
pipeline: 'pipeline-image-scan'
|
|
||||||
},
|
|
||||||
createTime: '2025-07-17 21:28:01',
|
|
||||||
updateTime: '2025-07-17 21:28:21',
|
|
||||||
startTime: '2025-07-17 21:28:01',
|
|
||||||
currentNodeMsg: '执行成功',
|
|
||||||
currentNodeStatus: 'success',
|
|
||||||
status: 'success'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 'node_approve_deploy',
|
|
||||||
type: 'service',
|
|
||||||
name: '部署审批',
|
|
||||||
click: false,
|
|
||||||
retry: true,
|
|
||||||
buttons: [
|
|
||||||
{
|
|
||||||
type: 'execute',
|
|
||||||
title: '同意',
|
|
||||||
code: 'agree',
|
|
||||||
parameters: {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'execute',
|
|
||||||
title: '拒绝',
|
|
||||||
code: 'refuse',
|
|
||||||
parameters: {}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
createTime: '2025-07-17 21:28:21',
|
|
||||||
updateTime: '2025-07-17 21:28:21',
|
|
||||||
startTime: '2025-07-17 21:28:21',
|
|
||||||
currentNodeMsg: '等待人工审批',
|
|
||||||
currentNodeStatus: 'running',
|
|
||||||
status: 'running'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 'node_deploy_java',
|
|
||||||
type: 'service',
|
|
||||||
name: '部署',
|
|
||||||
click: true,
|
|
||||||
retry: false,
|
|
||||||
buttons: [{
|
|
||||||
type: 'link',
|
|
||||||
title: '查看部署详情',
|
|
||||||
code: 'success',
|
|
||||||
parameters: {
|
|
||||||
'isBlank': true
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
createTime: '2025-07-17 21:28:21',
|
|
||||||
updateTime: '2025-07-17 21:28:21',
|
|
||||||
startTime: null,
|
|
||||||
currentNodeMsg: '待执行',
|
|
||||||
currentNodeStatus: 'pending',
|
|
||||||
status: 'pending'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 'node_merge_confirm',
|
|
||||||
type: 'service',
|
|
||||||
name: '合并确认',
|
|
||||||
click: false,
|
|
||||||
retry: false,
|
|
||||||
buttons: [{
|
|
||||||
type: 'execute',
|
|
||||||
title: '通过',
|
|
||||||
code: 'agree',
|
|
||||||
parameters: {}
|
|
||||||
}],
|
|
||||||
createTime: '2025-07-17 21:28:21',
|
|
||||||
updateTime: '2025-07-17 21:28:21',
|
|
||||||
startTime: null,
|
|
||||||
currentNodeMsg: '待执行',
|
|
||||||
currentNodeStatus: 'pending',
|
|
||||||
status: 'pending'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 'node_merge_master',
|
|
||||||
type: 'service',
|
|
||||||
name: '合并回Master',
|
|
||||||
click: false,
|
|
||||||
retry: true,
|
|
||||||
createTime: '2025-07-17 21:28:21',
|
|
||||||
updateTime: '2025-07-17 21:28:21',
|
|
||||||
startTime: null,
|
|
||||||
currentNodeMsg: '待执行',
|
|
||||||
currentNodeStatus: 'pending',
|
|
||||||
status: 'pending'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
// 成功
|
// 成功
|
||||||
dataList2: [
|
dataList2: [
|
||||||
{
|
{
|
||||||
@@ -576,21 +436,18 @@ export default {
|
|||||||
currentNodeStatus: 'pending',
|
currentNodeStatus: 'pending',
|
||||||
status: 'pending'
|
status: 'pending'
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
// 动态流水线
|
||||||
|
dynamicHook: null,
|
||||||
|
dynamicList: [],
|
||||||
|
dynamicInstanceId: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
setInterval(this.refreshData, 1000)
|
this.refreshData()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
refreshData() {
|
refreshData() {
|
||||||
// 运行中
|
|
||||||
for (const datum of this.dataList1) {
|
|
||||||
if (datum.status === 'running') {
|
|
||||||
datum.updateTime = formatDateTimeStr(new Date())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.dataList1 = [...this.dataList1]
|
|
||||||
// 成功
|
// 成功
|
||||||
for (const datum of this.dataList2) {
|
for (const datum of this.dataList2) {
|
||||||
if (datum.status === 'running') {
|
if (datum.status === 'running') {
|
||||||
@@ -605,6 +462,22 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.dataList3 = [...this.dataList3]
|
this.dataList3 = [...this.dataList3]
|
||||||
|
},
|
||||||
|
startPipelineTest() {
|
||||||
|
const that = this
|
||||||
|
if (that.dynamicHook) {
|
||||||
|
clearInterval(that.dynamicHook)
|
||||||
|
}
|
||||||
|
startPipeline().then((instanceId) => {
|
||||||
|
that.dynamicInstanceId = instanceId
|
||||||
|
setTimeout(() => {
|
||||||
|
that.dynamicHook = setInterval(() => {
|
||||||
|
queryLastPipelineDetail(that.dynamicInstanceId).then((data) => {
|
||||||
|
that.dynamicList = data
|
||||||
|
})
|
||||||
|
}, 1000)
|
||||||
|
}, 2000)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -22,10 +22,13 @@ public interface PipelineConst {
|
|||||||
// String INSTANCE_NODE_TEMPLATE_ARGS_KEY = "pipelineInstanceNodeTemplateArgs";
|
// String INSTANCE_NODE_TEMPLATE_ARGS_KEY = "pipelineInstanceNodeTemplateArgs";
|
||||||
// String INSTANCE_RETRY_NODE_INDEX_KEY = "pipelineInstanceRetryNodeIndex";
|
// String INSTANCE_RETRY_NODE_INDEX_KEY = "pipelineInstanceRetryNodeIndex";
|
||||||
// 以下为标准常量
|
// 以下为标准常量
|
||||||
|
String INSTANCE = "Instance";
|
||||||
String INSTANCE_ID = "InstanceId";
|
String INSTANCE_ID = "InstanceId";
|
||||||
|
String TEMPLATE = "Template";
|
||||||
String TEMPLATE_ID = "TemplateId";
|
String TEMPLATE_ID = "TemplateId";
|
||||||
String ENV = "Env";
|
String ENV = "Env";
|
||||||
String CONTEXT_NAME = "ContextName";
|
String CONTEXT_NAME = "ContextName";
|
||||||
String RETRY_NODE_CODE = "RetryNodeCode";
|
String RETRY_NODE_CODE = "RetryNodeCode";
|
||||||
String CURRENT_NODE_TEMPLATE = "CurrentNodeTemplate";
|
String CURRENT_NODE_TEMPLATE = "CurrentNodeTemplate";
|
||||||
|
String LAST_NODE_RESULT = "LastNodeResult";
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-5
@@ -3,27 +3,37 @@ package cn.odboy.devops.controller;
|
|||||||
import cn.odboy.annotation.AnonymousGetMapping;
|
import cn.odboy.annotation.AnonymousGetMapping;
|
||||||
import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
||||||
import cn.odboy.devops.dal.dataobject.PipelineTemplateTb;
|
import cn.odboy.devops.dal.dataobject.PipelineTemplateTb;
|
||||||
|
import cn.odboy.devops.dal.model.DevOpsQueryLastPipelineDetailArgs;
|
||||||
import cn.odboy.devops.service.PipelineInstanceService;
|
import cn.odboy.devops.service.PipelineInstanceService;
|
||||||
import cn.odboy.devops.service.PipelineTemplateService;
|
import cn.odboy.devops.service.PipelineTemplateService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@RestController
|
@RestController
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@RequestMapping("/api/devops/pipeline")
|
@RequestMapping("/api/devops/pipeline")
|
||||||
@Api(tags = "系统:验证码管理")
|
@Api(tags = "DevOps:流水线管理")
|
||||||
public class DevopsPipelineController {
|
public class DevopsPipelineController {
|
||||||
@Autowired
|
@Autowired
|
||||||
private PipelineTemplateService pipelineTemplateService;
|
private PipelineTemplateService pipelineTemplateService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private PipelineInstanceService pipelineInstanceService;
|
private PipelineInstanceService pipelineInstanceService;
|
||||||
|
|
||||||
@AnonymousGetMapping(value = "/start")
|
@ApiOperation("启动流水线")
|
||||||
public ResponseEntity<?> start() {
|
@PostMapping(value = "/start")
|
||||||
|
@PreAuthorize("@el.check()")
|
||||||
|
public ResponseEntity<?> startPipeline() {
|
||||||
// 输入参数
|
// 输入参数
|
||||||
String appName = "cuteops";
|
String appName = "cuteops";
|
||||||
String envCode = "daily";
|
String envCode = "daily";
|
||||||
@@ -37,7 +47,33 @@ public class DevopsPipelineController {
|
|||||||
pipelineInstanceTb.setContextName(appName);
|
pipelineInstanceTb.setContextName(appName);
|
||||||
pipelineInstanceTb.setEnv(envCode);
|
pipelineInstanceTb.setEnv(envCode);
|
||||||
pipelineInstanceTb.setTemplateContent(pipelineTemplateTb.getTemplate());
|
pipelineInstanceTb.setTemplateContent(pipelineTemplateTb.getTemplate());
|
||||||
pipelineInstanceService.start(pipelineInstanceTb);
|
return ResponseEntity.ok(pipelineInstanceService.startPipeline(pipelineInstanceTb));
|
||||||
return ResponseEntity.ok("流水线启动成功");
|
}
|
||||||
|
|
||||||
|
@ApiOperation("重启流水线")
|
||||||
|
@PostMapping(value = "/restart")
|
||||||
|
@PreAuthorize("@el.check()")
|
||||||
|
public ResponseEntity<?> restartPipeline() {
|
||||||
|
String appName = "cuteops";
|
||||||
|
String envCode = "daily";
|
||||||
|
PipelineTemplateTb pipelineTemplateTb = pipelineTemplateService.getPipelineTemplateById(4L);
|
||||||
|
PipelineInstanceTb pipelineInstanceTb = new PipelineInstanceTb();
|
||||||
|
pipelineInstanceTb.setTemplateId(pipelineTemplateTb.getId());
|
||||||
|
pipelineInstanceTb.setInstanceName("流水线测试");
|
||||||
|
pipelineInstanceTb.setTemplateType(pipelineTemplateTb.getType());
|
||||||
|
pipelineInstanceTb.setContextName(appName);
|
||||||
|
pipelineInstanceTb.setEnv(envCode);
|
||||||
|
pipelineInstanceTb.setTemplateContent(pipelineTemplateTb.getTemplate());
|
||||||
|
pipelineInstanceTb.setInstanceId(1947604330727079936L);
|
||||||
|
String retryNodeCode = "node_build_java";
|
||||||
|
pipelineInstanceService.restartPipeline(pipelineInstanceTb, retryNodeCode);
|
||||||
|
return ResponseEntity.ok("流水线重启成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("查询流水线明细")
|
||||||
|
@PostMapping(value = "/last")
|
||||||
|
@PreAuthorize("@el.check()")
|
||||||
|
public ResponseEntity<?> queryLastPipelineDetail(@Validated @RequestBody DevOpsQueryLastPipelineDetailArgs args) {
|
||||||
|
return ResponseEntity.ok(pipelineInstanceService.queryLastPipelineDetail(args.getInstanceId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-6
@@ -32,7 +32,7 @@ public class PipelineInstanceNodeDetailTb extends CsObject {
|
|||||||
* 流水线节点Id
|
* 流水线节点Id
|
||||||
*/
|
*/
|
||||||
@CollectionField("node_id")
|
@CollectionField("node_id")
|
||||||
private String nodeId;
|
private Long nodeId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 开始时间
|
* 开始时间
|
||||||
@@ -46,11 +46,6 @@ public class PipelineInstanceNodeDetailTb extends CsObject {
|
|||||||
@CollectionField("finish_time")
|
@CollectionField("finish_time")
|
||||||
private Date finishTime;
|
private Date finishTime;
|
||||||
|
|
||||||
/**
|
|
||||||
* 节点索引
|
|
||||||
*/
|
|
||||||
@CollectionField("node_index")
|
|
||||||
private Integer nodeIndex;
|
|
||||||
/**
|
/**
|
||||||
* 节点编码
|
* 节点编码
|
||||||
*/
|
*/
|
||||||
|
|||||||
+2
-5
@@ -72,6 +72,8 @@ public class PipelineInstanceNodeTb extends CsObject {
|
|||||||
private Date updateTime;
|
private Date updateTime;
|
||||||
@CollectionField("start_time")
|
@CollectionField("start_time")
|
||||||
private Date startTime;
|
private Date startTime;
|
||||||
|
@CollectionField("finish_time")
|
||||||
|
private Date finishTime;
|
||||||
/**
|
/**
|
||||||
* 节点状态
|
* 节点状态
|
||||||
*/
|
*/
|
||||||
@@ -79,9 +81,4 @@ public class PipelineInstanceNodeTb extends CsObject {
|
|||||||
private String currentNodeMsg = PipelineStatusEnum.PENDING.getDesc();
|
private String currentNodeMsg = PipelineStatusEnum.PENDING.getDesc();
|
||||||
@CollectionField("current_node_status")
|
@CollectionField("current_node_status")
|
||||||
private String currentNodeStatus = PipelineStatusEnum.PENDING.getCode();
|
private String currentNodeStatus = PipelineStatusEnum.PENDING.getCode();
|
||||||
/**
|
|
||||||
* 节点状态
|
|
||||||
*/
|
|
||||||
@CollectionField("status")
|
|
||||||
private String status = PipelineStatusEnum.PENDING.getCode();
|
|
||||||
}
|
}
|
||||||
|
|||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package cn.odboy.devops.dal.model;
|
||||||
|
|
||||||
|
import cn.odboy.base.CsObject;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class DevOpsQueryLastPipelineDetailArgs extends CsObject {
|
||||||
|
@NotBlank(message = "流水线实例Id必填")
|
||||||
|
private String instanceId;
|
||||||
|
}
|
||||||
+2
-2
@@ -20,8 +20,8 @@ public class PipelineInstanceDAO {
|
|||||||
if (o != null) {
|
if (o != null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// 365天
|
// 3个月
|
||||||
redisHelper.set(redisKey, true, 60 * 60 * 24 * 365);
|
redisHelper.set(redisKey, true, 60 * 60 * 24 * 90);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
package cn.odboy.devops.framework.pipeline;
|
||||||
|
|
||||||
|
import cn.odboy.devops.constant.pipeline.PipelineStatusEnum;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
|
import cn.odboy.devops.service.PipelineInstanceNodeDetailService;
|
||||||
|
import cn.odboy.devops.service.PipelineInstanceNodeService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public abstract class AbstractPipelineNodeJobService {
|
||||||
|
// @Autowired
|
||||||
|
// private PipelineTemplateService pipelineTemplateService;
|
||||||
|
// @Autowired
|
||||||
|
// private PipelineInstanceService pipelineInstanceService;
|
||||||
|
@Autowired
|
||||||
|
private PipelineInstanceNodeService pipelineInstanceNodeService;
|
||||||
|
@Autowired
|
||||||
|
private PipelineInstanceNodeDetailService pipelineInstanceNodeDetailService;
|
||||||
|
|
||||||
|
public PipelineInstanceNodeTb getCurrentNodeInfo(long instanceId, String code) {
|
||||||
|
return pipelineInstanceNodeService.getPipelineInstanceNodeByArgs(instanceId, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addLog(PipelineInstanceNodeTb pipelineInstanceNode, String stepName, PipelineStatusEnum stepStatus, String stepMsg, Date finishTime) {
|
||||||
|
if (pipelineInstanceNode != null) {
|
||||||
|
pipelineInstanceNodeDetailService.addLog(pipelineInstanceNode.getId(), pipelineInstanceNode.getCode(), stepName, stepStatus, stepMsg, finishTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+205
@@ -0,0 +1,205 @@
|
|||||||
|
package cn.odboy.devops.framework.pipeline.core;
|
||||||
|
|
||||||
|
import cn.hutool.core.thread.ThreadUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
||||||
|
import cn.odboy.devops.constant.pipeline.PipelineStatusEnum;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
||||||
|
import cn.odboy.devops.dal.mysql.PipelineInstanceMapper;
|
||||||
|
import cn.odboy.devops.dal.redis.PipelineInstanceDAO;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
|
import cn.odboy.devops.service.PipelineInstanceNodeService;
|
||||||
|
import cn.odboy.framework.context.SpringBeanHolder;
|
||||||
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.quartz.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流水线任务载体
|
||||||
|
*
|
||||||
|
* @author odboy
|
||||||
|
* @date 2025-07-19
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class PipelineJobBean implements InterruptableJob {
|
||||||
|
private volatile boolean interrupted = false;
|
||||||
|
private volatile Long currentInstanceId = null;
|
||||||
|
private volatile String currentNodeCode = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
||||||
|
// 获取服务
|
||||||
|
PipelineInstanceMapper pipelineInstanceMapper = SpringBeanHolder.getBean(PipelineInstanceMapper.class);
|
||||||
|
PipelineInstanceNodeService pipelineInstanceNodeService = SpringBeanHolder.getBean(PipelineInstanceNodeService.class);
|
||||||
|
PipelineInstanceDAO pipelineInstanceDAO = SpringBeanHolder.getBean(PipelineInstanceDAO.class);
|
||||||
|
PipelineJobManage pipelineJobManage = SpringBeanHolder.getBean(PipelineJobManage.class);
|
||||||
|
PipelineNodeJobManage pipelineNodeJobManage = SpringBeanHolder.getBean(PipelineNodeJobManage.class);
|
||||||
|
|
||||||
|
// 参数解析
|
||||||
|
JobDataMap jobDataMap = jobExecutionContext.getMergedJobDataMap();
|
||||||
|
String retryNodeCode = jobDataMap.getString(PipelineConst.RETRY_NODE_CODE);
|
||||||
|
PipelineInstanceTb pipelineInstanceTb = (PipelineInstanceTb) jobDataMap.get(PipelineConst.INSTANCE);
|
||||||
|
pipelineInstanceTb.setStatus(PipelineStatusEnum.PENDING.getCode());
|
||||||
|
|
||||||
|
// // 模拟终止流水线
|
||||||
|
// ThreadUtil.execAsync(() -> {
|
||||||
|
// ThreadUtil.safeSleep(6000);
|
||||||
|
// try {
|
||||||
|
// pipelineJobManage.interruptJob(pipelineInstanceTb.getInstanceId());
|
||||||
|
// } catch (SchedulerException e) {
|
||||||
|
// log.error("终止流水线异常", e);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
if (StrUtil.isBlank(retryNodeCode)) {
|
||||||
|
// 创建实例
|
||||||
|
pipelineInstanceMapper.insert(pipelineInstanceTb);
|
||||||
|
// 创建实例明细
|
||||||
|
pipelineInstanceNodeService.createPipelineInstanceDetail(pipelineInstanceTb);
|
||||||
|
} else {
|
||||||
|
// 重建实例明细
|
||||||
|
pipelineInstanceNodeService.remakePipelineInstanceDetail(pipelineInstanceTb, retryNodeCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实例节点模板
|
||||||
|
String templateContent = pipelineInstanceTb.getTemplateContent();
|
||||||
|
List<PipelineNodeTemplateVo> pipelineNodeTemplateVos = JSON.parseArray(templateContent, PipelineNodeTemplateVo.class);
|
||||||
|
Long instanceId = pipelineInstanceTb.getInstanceId();
|
||||||
|
|
||||||
|
// 实例状态(默认是成功的)
|
||||||
|
PipelineStatusEnum pipelineStatusEnum = PipelineStatusEnum.SUCCESS;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 更新实例状态(running)
|
||||||
|
pipelineInstanceTb.setStatus(PipelineStatusEnum.RUNNING.getCode());
|
||||||
|
pipelineInstanceMapper.updateById(pipelineInstanceTb);
|
||||||
|
|
||||||
|
// 依次执行流水线节点任务
|
||||||
|
boolean skipFlag = true;
|
||||||
|
boolean foundRetryNode = false;
|
||||||
|
this.currentInstanceId = pipelineInstanceTb.getInstanceId();
|
||||||
|
for (PipelineNodeTemplateVo pipelineNodeTemplateVo : pipelineNodeTemplateVos) {
|
||||||
|
this.currentNodeCode = pipelineNodeTemplateVo.getCode();
|
||||||
|
|
||||||
|
// 如果 retryNodeCode 不为空,进入跳过逻辑
|
||||||
|
if (StrUtil.isNotBlank(retryNodeCode)) {
|
||||||
|
if (skipFlag && !pipelineNodeTemplateVo.getCode().equals(retryNodeCode)) {
|
||||||
|
// 如果当前节点不是重试节点,且 skipFlag 为 true,则跳过
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
// 找到重试节点,开始执行
|
||||||
|
skipFlag = false;
|
||||||
|
foundRetryNode = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StrUtil.isNotBlank(retryNodeCode) && !foundRetryNode) {
|
||||||
|
log.error("未找到重试节点: {}", retryNodeCode);
|
||||||
|
throw new BadRequestException("未找到重试节点: " + retryNodeCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
pipelineNodeJobManage.startJob(pipelineInstanceTb, pipelineNodeTemplateVo);
|
||||||
|
pipelineInstanceTb.setCurrentNode(pipelineNodeTemplateVo.getCode());
|
||||||
|
pipelineInstanceTb.setCurrentNodeStatus(PipelineStatusEnum.RUNNING.getCode());
|
||||||
|
pipelineInstanceMapper.updateById(pipelineInstanceTb);
|
||||||
|
|
||||||
|
// 监听节点执行状态
|
||||||
|
while (true) {
|
||||||
|
// 检查中断状态
|
||||||
|
// if (Thread.currentThread().isInterrupted() || interrupted) {
|
||||||
|
if (interrupted) {
|
||||||
|
log.error("检测到中断,停止流水线执行");
|
||||||
|
pipelineStatusEnum = PipelineStatusEnum.FAIL;
|
||||||
|
pipelineInstanceTb.setCurrentNode(pipelineNodeTemplateVo.getCode());
|
||||||
|
pipelineInstanceTb.setCurrentNodeStatus(pipelineStatusEnum.getCode());
|
||||||
|
pipelineInstanceMapper.updateById(pipelineInstanceTb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
PipelineInstanceNodeTb pipelineInstanceNode = pipelineInstanceNodeService.getPipelineInstanceNodeByArgs(instanceId, pipelineNodeTemplateVo.getCode());
|
||||||
|
if (PipelineStatusEnum.SUCCESS.getCode().equals(pipelineInstanceNode.getCurrentNodeStatus())) {
|
||||||
|
pipelineStatusEnum = PipelineStatusEnum.SUCCESS;
|
||||||
|
pipelineInstanceTb.setCurrentNodeStatus(pipelineStatusEnum.getCode());
|
||||||
|
pipelineInstanceMapper.updateById(pipelineInstanceTb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (PipelineStatusEnum.FAIL.getCode().equals(pipelineInstanceNode.getCurrentNodeStatus())) {
|
||||||
|
pipelineStatusEnum = PipelineStatusEnum.FAIL;
|
||||||
|
pipelineInstanceTb.setCurrentNodeStatus(pipelineStatusEnum.getCode());
|
||||||
|
pipelineInstanceMapper.updateById(pipelineInstanceTb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pipelineStatusEnum.equals(PipelineStatusEnum.FAIL)) {
|
||||||
|
// 节点失败,全失败
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("流水线节点运行失败", e);
|
||||||
|
pipelineInstanceTb.setStatus(PipelineStatusEnum.FAIL.getCode());
|
||||||
|
pipelineInstanceMapper.updateById(pipelineInstanceTb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新实例状态
|
||||||
|
pipelineInstanceTb.setStatus(pipelineStatusEnum.getCode());
|
||||||
|
pipelineInstanceMapper.updateById(pipelineInstanceTb);
|
||||||
|
pipelineInstanceDAO.unLock(pipelineInstanceTb);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("流水线运行失败", e);
|
||||||
|
pipelineInstanceTb.setStatus(PipelineStatusEnum.FAIL.getCode());
|
||||||
|
pipelineInstanceMapper.updateById(pipelineInstanceTb);
|
||||||
|
pipelineInstanceDAO.unLock(pipelineInstanceTb);
|
||||||
|
} finally {
|
||||||
|
pipelineJobManage.deleteJob(instanceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流水线任务已中断
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void interrupt() throws UnableToInterruptJobException {
|
||||||
|
this.interrupted = true;
|
||||||
|
if (this.currentInstanceId != null && StrUtil.isNotBlank(this.currentNodeCode)) {
|
||||||
|
PipelineInstanceMapper pipelineInstanceMapper = SpringBeanHolder.getBean(PipelineInstanceMapper.class);
|
||||||
|
PipelineInstanceDAO pipelineInstanceDAO = SpringBeanHolder.getBean(PipelineInstanceDAO.class);
|
||||||
|
|
||||||
|
int seconds = 30_000;
|
||||||
|
log.info("中断信号已发出,等待最多 {} 秒,若未自行结束则强制终止线程", seconds);
|
||||||
|
long waitStart = System.currentTimeMillis();
|
||||||
|
while ((System.currentTimeMillis() - waitStart) < seconds) {
|
||||||
|
if (Thread.currentThread().isInterrupted()) {
|
||||||
|
log.info("线程已自行中断");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ThreadUtil.safeSleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("等待超时,强制终止线程");
|
||||||
|
PipelineInstanceTb pipelineInstanceTb = pipelineInstanceMapper.selectById(this.currentInstanceId);
|
||||||
|
if (pipelineInstanceTb != null) {
|
||||||
|
// 更新状态 & 解锁
|
||||||
|
pipelineInstanceTb.setCurrentNode(this.currentNodeCode);
|
||||||
|
pipelineInstanceTb.setCurrentNodeStatus(PipelineStatusEnum.FAIL.getCode());
|
||||||
|
pipelineInstanceTb.setStatus(PipelineStatusEnum.FAIL.getCode());
|
||||||
|
pipelineInstanceMapper.updateById(pipelineInstanceTb);
|
||||||
|
pipelineInstanceDAO.unLock(pipelineInstanceTb);
|
||||||
|
|
||||||
|
// 杀死
|
||||||
|
try {
|
||||||
|
log.info("流水线实例线程被杀死, instanceId={}", this.currentInstanceId);
|
||||||
|
Thread.currentThread().stop();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("流水线实例线程杀死失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+44
-26
@@ -1,15 +1,14 @@
|
|||||||
package cn.odboy.devops.framework.pipeline.core;
|
package cn.odboy.devops.framework.pipeline.core;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
||||||
import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
|
||||||
import cn.odboy.framework.exception.BadRequestException;
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.quartz.*;
|
import org.quartz.*;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流水线任务管理器
|
* 流水线任务管理器
|
||||||
@@ -20,37 +19,29 @@ import javax.validation.constraints.NotNull;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
public class PipelineJobManage {
|
public class PipelineJobManage {
|
||||||
private static final String JOB_KEY = "PIPELINE_JOB_%s_%s";
|
private static final String JOB_KEY = "PIPELINE_JOB_%s";
|
||||||
@Resource
|
@Resource
|
||||||
private Scheduler scheduler;
|
private Scheduler scheduler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启动 job
|
* 启动 job
|
||||||
*/
|
*/
|
||||||
public void startJob(PipelineInstanceTb pipelineInstance, PipelineNodeTemplateVo pipelineNodeTemplate) {
|
public String startJob(PipelineInstanceTb pipelineInstance) {
|
||||||
|
// 流水线Id(雪花)
|
||||||
|
Long instanceId = IdUtil.getSnowflakeNextId();
|
||||||
try {
|
try {
|
||||||
// 流水线Id
|
pipelineInstance.setInstanceId(instanceId);
|
||||||
Long instanceId = pipelineInstance.getInstanceId();
|
String keyName = String.format(JOB_KEY, instanceId);
|
||||||
String jobId = String.format(JOB_KEY, instanceId, pipelineNodeTemplate.getCode());
|
|
||||||
// 构建 JobDetail
|
// 构建 JobDetail
|
||||||
JobKey jobKey = JobKey.jobKey(jobId);
|
JobKey jobKey = JobKey.jobKey(keyName);
|
||||||
JobDetail jobDetail = JobBuilder
|
JobDetail jobDetail = JobBuilder.newJob(PipelineJobBean.class).withIdentity(jobKey).build();
|
||||||
.newJob(PipelineNodeJobBean.class)
|
|
||||||
.withIdentity(jobKey)
|
|
||||||
.build();
|
|
||||||
// 构建Trigger
|
// 构建Trigger
|
||||||
TriggerKey triggerKey = TriggerKey.triggerKey(String.format(JOB_KEY, instanceId, pipelineNodeTemplate.getCode()));
|
TriggerKey triggerKey = TriggerKey.triggerKey(keyName);
|
||||||
Trigger cronTrigger = TriggerBuilder.newTrigger()
|
Trigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).startNow().build();
|
||||||
.withIdentity(triggerKey)
|
|
||||||
.startNow()
|
|
||||||
.build();
|
|
||||||
// 任务参数
|
// 任务参数
|
||||||
JobDataMap jobDataMap = cronTrigger.getJobDataMap();
|
JobDataMap jobDataMap = cronTrigger.getJobDataMap();
|
||||||
jobDataMap.put(PipelineConst.INSTANCE_ID, pipelineInstance.getInstanceId());
|
jobDataMap.put(PipelineConst.INSTANCE, pipelineInstance);
|
||||||
jobDataMap.put(PipelineConst.CONTEXT_NAME, pipelineInstance.getContextName());
|
jobDataMap.put(PipelineConst.RETRY_NODE_CODE, "");
|
||||||
jobDataMap.put(PipelineConst.ENV, pipelineInstance.getEnv());
|
|
||||||
jobDataMap.put(PipelineConst.TEMPLATE_ID, pipelineInstance.getTemplateId());
|
|
||||||
jobDataMap.put(PipelineConst.CURRENT_NODE_TEMPLATE, pipelineNodeTemplate);
|
|
||||||
try {
|
try {
|
||||||
// 在quartz的内部线程池中异步执行
|
// 在quartz的内部线程池中异步执行
|
||||||
scheduler.scheduleJob(jobDetail, cronTrigger);
|
scheduler.scheduleJob(jobDetail, cronTrigger);
|
||||||
@@ -61,14 +52,15 @@ public class PipelineJobManage {
|
|||||||
log.error("创建定时任务失败", e);
|
log.error("创建定时任务失败", e);
|
||||||
throw new BadRequestException("创建定时任务失败");
|
throw new BadRequestException("创建定时任务失败");
|
||||||
}
|
}
|
||||||
|
return String.valueOf(instanceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除job
|
* 删除job
|
||||||
*/
|
*/
|
||||||
public void deleteJob(@NotNull String instanceId, @NotNull String nodeCode) {
|
public void deleteJob(Long instanceId) {
|
||||||
try {
|
try {
|
||||||
JobKey jobKey = JobKey.jobKey(String.format(JOB_KEY, instanceId, nodeCode));
|
JobKey jobKey = JobKey.jobKey(String.format(JOB_KEY, instanceId));
|
||||||
scheduler.pauseJob(jobKey);
|
scheduler.pauseJob(jobKey);
|
||||||
scheduler.deleteJob(jobKey);
|
scheduler.deleteJob(jobKey);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -81,8 +73,34 @@ public class PipelineJobManage {
|
|||||||
* 中断正在执行的任务<br/>
|
* 中断正在执行的任务<br/>
|
||||||
* 任务终止需要配合响应中断或停止信号
|
* 任务终止需要配合响应中断或停止信号
|
||||||
*/
|
*/
|
||||||
public void interruptJob(@NotNull String instanceId, @NotNull String nodeCode) throws SchedulerException {
|
public void interruptJob(Long instanceId) throws SchedulerException {
|
||||||
JobKey jobKey = JobKey.jobKey(String.format(JOB_KEY, instanceId, nodeCode));
|
JobKey jobKey = JobKey.jobKey(String.format(JOB_KEY, instanceId));
|
||||||
scheduler.interrupt(jobKey);
|
scheduler.interrupt(jobKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void startJobByNodeCode(PipelineInstanceTb pipelineInstance, String retryNodeCode) {
|
||||||
|
try {
|
||||||
|
Long instanceId = pipelineInstance.getInstanceId();
|
||||||
|
String keyName = String.format(JOB_KEY, instanceId);
|
||||||
|
// 构建 JobDetail
|
||||||
|
JobKey jobKey = JobKey.jobKey(keyName);
|
||||||
|
JobDetail jobDetail = JobBuilder.newJob(PipelineJobBean.class).withIdentity(jobKey).build();
|
||||||
|
// 构建Trigger
|
||||||
|
TriggerKey triggerKey = TriggerKey.triggerKey(keyName);
|
||||||
|
Trigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).startNow().build();
|
||||||
|
// 任务参数
|
||||||
|
JobDataMap jobDataMap = cronTrigger.getJobDataMap();
|
||||||
|
jobDataMap.put(PipelineConst.INSTANCE, pipelineInstance);
|
||||||
|
jobDataMap.put(PipelineConst.RETRY_NODE_CODE, retryNodeCode);
|
||||||
|
try {
|
||||||
|
// 在quartz的内部线程池中异步执行
|
||||||
|
scheduler.scheduleJob(jobDetail, cronTrigger);
|
||||||
|
} catch (ObjectAlreadyExistsException e) {
|
||||||
|
log.warn("定时任务已存在,跳过加载");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("创建定时任务失败", e);
|
||||||
|
throw new BadRequestException("创建定时任务失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-9
@@ -1,10 +1,19 @@
|
|||||||
package cn.odboy.devops.framework.pipeline.core;
|
package cn.odboy.devops.framework.pipeline.core;
|
||||||
|
|
||||||
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
||||||
|
import cn.odboy.devops.constant.pipeline.PipelineStatusEnum;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
|
import cn.odboy.devops.service.PipelineInstanceNodeService;
|
||||||
import cn.odboy.framework.context.SpringBeanHolder;
|
import cn.odboy.framework.context.SpringBeanHolder;
|
||||||
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.quartz.*;
|
import org.quartz.Job;
|
||||||
|
import org.quartz.JobDataMap;
|
||||||
|
import org.quartz.JobExecutionContext;
|
||||||
|
import org.quartz.JobExecutionException;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流水线任务载体
|
* 流水线任务载体
|
||||||
@@ -13,18 +22,29 @@ import org.quartz.*;
|
|||||||
* @date 2025-07-19
|
* @date 2025-07-19
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class PipelineNodeJobBean implements InterruptableJob {
|
public class PipelineNodeJobBean implements Job {
|
||||||
@Override
|
@Override
|
||||||
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
||||||
|
PipelineInstanceNodeService pipelineInstanceNodeService = SpringBeanHolder.getBean(PipelineInstanceNodeService.class);
|
||||||
|
|
||||||
JobDataMap jobDataMap = jobExecutionContext.getMergedJobDataMap();
|
JobDataMap jobDataMap = jobExecutionContext.getMergedJobDataMap();
|
||||||
|
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
||||||
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
||||||
String serviceName = PipelineConst.EXECUTOR_PREFIX + currentNodeTemplate.getCode();
|
String nodeCode = currentNodeTemplate.getCode();
|
||||||
PipelineNodeJobExecutor pipelineNodeJobExecutor = SpringBeanHolder.getBean(serviceName);
|
|
||||||
pipelineNodeJobExecutor.execute(jobDataMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void interrupt() throws UnableToInterruptJobException {
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
String serviceName = PipelineConst.EXECUTOR_PREFIX + nodeCode;
|
||||||
|
PipelineNodeJobExecutor pipelineNodeJobExecutor = SpringBeanHolder.getBean(serviceName);
|
||||||
|
pipelineInstanceNodeService.updatePipelineInstanceNodeByArgs(instanceId, nodeCode, PipelineStatusEnum.RUNNING, PipelineStatusEnum.RUNNING.getDesc());
|
||||||
|
PipelineNodeJobExecuteResult executeResult = pipelineNodeJobExecutor.execute(jobDataMap);
|
||||||
|
jobExecutionContext.getMergedJobDataMap().put(PipelineConst.LAST_NODE_RESULT, executeResult);
|
||||||
|
pipelineInstanceNodeService.finishPipelineInstanceNodeByArgs(instanceId, nodeCode, PipelineStatusEnum.SUCCESS, PipelineStatusEnum.SUCCESS.getDesc(), new Date());
|
||||||
|
} catch (BadRequestException e) {
|
||||||
|
log.error("流水线节点执行异常", e);
|
||||||
|
pipelineInstanceNodeService.finishPipelineInstanceNodeByArgs(instanceId, nodeCode, PipelineStatusEnum.FAIL, e.getMessage(), new Date());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("流水线节点执行异常", e);
|
||||||
|
pipelineInstanceNodeService.finishPipelineInstanceNodeByArgs(instanceId, nodeCode, PipelineStatusEnum.FAIL, PipelineStatusEnum.FAIL.getDesc(), new Date());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
package cn.odboy.devops.framework.pipeline.core;
|
package cn.odboy.devops.framework.pipeline.core;
|
||||||
|
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
||||||
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
import org.quartz.JobDataMap;
|
import org.quartz.JobDataMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,5 +11,5 @@ import org.quartz.JobDataMap;
|
|||||||
* @date 2025-07-21
|
* @date 2025-07-21
|
||||||
*/
|
*/
|
||||||
public interface PipelineNodeJobExecutor {
|
public interface PipelineNodeJobExecutor {
|
||||||
PipelineNodeJobExecuteResult execute(JobDataMap contextArgs);
|
PipelineNodeJobExecuteResult execute(JobDataMap contextArgs) throws BadRequestException;
|
||||||
}
|
}
|
||||||
|
|||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
package cn.odboy.devops.framework.pipeline.core;
|
||||||
|
|
||||||
|
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.quartz.*;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流水线任务管理器
|
||||||
|
*
|
||||||
|
* @author odboy
|
||||||
|
* @date 2025-07-19
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class PipelineNodeJobManage {
|
||||||
|
private static final String JOB_KEY = "PIPELINE_NODE_JOB_%s_%s";
|
||||||
|
@Resource
|
||||||
|
private Scheduler scheduler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动 job
|
||||||
|
*/
|
||||||
|
public void startJob(PipelineInstanceTb pipelineInstance, PipelineNodeTemplateVo pipelineNodeTemplate) {
|
||||||
|
try {
|
||||||
|
// 流水线Id
|
||||||
|
Long instanceId = pipelineInstance.getInstanceId();
|
||||||
|
String keyName = String.format(JOB_KEY, instanceId, pipelineNodeTemplate.getCode());
|
||||||
|
// 构建 JobDetail
|
||||||
|
JobKey jobKey = JobKey.jobKey(keyName);
|
||||||
|
JobDetail jobDetail = JobBuilder
|
||||||
|
.newJob(PipelineNodeJobBean.class)
|
||||||
|
.withIdentity(jobKey)
|
||||||
|
.build();
|
||||||
|
// 构建Trigger
|
||||||
|
TriggerKey triggerKey = TriggerKey.triggerKey(keyName);
|
||||||
|
Trigger cronTrigger = TriggerBuilder.newTrigger()
|
||||||
|
.withIdentity(triggerKey)
|
||||||
|
.startNow()
|
||||||
|
.build();
|
||||||
|
// 任务参数
|
||||||
|
JobDataMap jobDataMap = cronTrigger.getJobDataMap();
|
||||||
|
jobDataMap.put(PipelineConst.INSTANCE_ID, pipelineInstance.getInstanceId());
|
||||||
|
jobDataMap.put(PipelineConst.CONTEXT_NAME, pipelineInstance.getContextName());
|
||||||
|
jobDataMap.put(PipelineConst.ENV, pipelineInstance.getEnv());
|
||||||
|
jobDataMap.put(PipelineConst.TEMPLATE, pipelineInstance.getTemplateContent());
|
||||||
|
jobDataMap.put(PipelineConst.TEMPLATE_ID, pipelineInstance.getTemplateId());
|
||||||
|
jobDataMap.put(PipelineConst.CURRENT_NODE_TEMPLATE, pipelineNodeTemplate);
|
||||||
|
try {
|
||||||
|
// 在quartz的内部线程池中异步执行
|
||||||
|
scheduler.scheduleJob(jobDetail, cronTrigger);
|
||||||
|
} catch (ObjectAlreadyExistsException e) {
|
||||||
|
log.warn("定时任务已存在,跳过加载");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("创建定时任务失败", e);
|
||||||
|
throw new BadRequestException("创建定时任务失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除job
|
||||||
|
*/
|
||||||
|
public void deleteJob(@NotNull String instanceId, @NotNull String nodeCode) {
|
||||||
|
try {
|
||||||
|
JobKey jobKey = JobKey.jobKey(String.format(JOB_KEY, instanceId, nodeCode));
|
||||||
|
scheduler.pauseJob(jobKey);
|
||||||
|
scheduler.deleteJob(jobKey);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("删除定时任务失败", e);
|
||||||
|
throw new BadRequestException("删除定时任务失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 中断正在执行的任务<br/>
|
||||||
|
* 任务终止需要配合响应中断或停止信号
|
||||||
|
*/
|
||||||
|
public void interruptJob(@NotNull String instanceId, @NotNull String nodeCode) throws SchedulerException {
|
||||||
|
JobKey jobKey = JobKey.jobKey(String.format(JOB_KEY, instanceId, nodeCode));
|
||||||
|
scheduler.interrupt(jobKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package cn.odboy.devops.framework.pipeline.log;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流水线节点明细日志 切面
|
||||||
|
*
|
||||||
|
* @author odboy
|
||||||
|
* @date 2025-07-22
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
public @interface PipelineNodeStepLog {
|
||||||
|
String value() default "默认步骤名";
|
||||||
|
}
|
||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
package cn.odboy.devops.framework.pipeline.log;
|
||||||
|
|
||||||
|
import cn.odboy.devops.constant.pipeline.PipelineStatusEnum;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
|
import cn.odboy.devops.framework.pipeline.AbstractPipelineNodeJobService;
|
||||||
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class PipelineNodeStepLogAspect extends AbstractPipelineNodeJobService {
|
||||||
|
/**
|
||||||
|
* 配置切入点
|
||||||
|
*/
|
||||||
|
@Pointcut("@annotation(cn.odboy.devops.framework.pipeline.log.PipelineNodeStepLog)")
|
||||||
|
public void logPointcut() {
|
||||||
|
// 该方法无方法体,主要为了让同类中其他方法使用此切入点
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置环绕通知,使用在方法logPointcut()上注册的切入点
|
||||||
|
*
|
||||||
|
* @param joinPoint join point for advice
|
||||||
|
*/
|
||||||
|
@Around("logPointcut()")
|
||||||
|
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||||
|
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||||
|
Method method = signature.getMethod();
|
||||||
|
PipelineInstanceNodeTb currentNodeInfo = null;
|
||||||
|
for (Object arg : joinPoint.getArgs()) {
|
||||||
|
if (arg instanceof PipelineInstanceNodeTb) {
|
||||||
|
currentNodeInfo = (PipelineInstanceNodeTb) arg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PipelineNodeStepLog pipelineNodeStepLog = method.getAnnotation(PipelineNodeStepLog.class);
|
||||||
|
try {
|
||||||
|
addLog(currentNodeInfo, pipelineNodeStepLog.value(), PipelineStatusEnum.RUNNING, PipelineStatusEnum.RUNNING.getDesc(), null);
|
||||||
|
Object result = joinPoint.proceed();
|
||||||
|
addLog(currentNodeInfo, pipelineNodeStepLog.value(), PipelineStatusEnum.SUCCESS, PipelineStatusEnum.SUCCESS.getDesc(), new Date());
|
||||||
|
return result;
|
||||||
|
} catch (BadRequestException e) {
|
||||||
|
log.error("执行失败", e);
|
||||||
|
addLog(currentNodeInfo, pipelineNodeStepLog.value(), PipelineStatusEnum.FAIL, e.getMessage(), new Date());
|
||||||
|
throw e;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error("执行失败", e);
|
||||||
|
addLog(currentNodeInfo, pipelineNodeStepLog.value(), PipelineStatusEnum.FAIL, PipelineStatusEnum.FAIL.getDesc(), new Date());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
package cn.odboy.devops.framework.pipeline.model;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流水线节点数据
|
||||||
|
*
|
||||||
|
* @author odboy
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class PipelineNodeDataVo extends PipelineNodeTemplateVo {
|
||||||
|
/**
|
||||||
|
* 节点创建时间
|
||||||
|
*/
|
||||||
|
private Date createTime;
|
||||||
|
/**
|
||||||
|
* 节点更新时间
|
||||||
|
*/
|
||||||
|
private Date updateTime;
|
||||||
|
/**
|
||||||
|
* 节点开始运行时间
|
||||||
|
*/
|
||||||
|
private Date startTime;
|
||||||
|
/**
|
||||||
|
* 节点结束运行时间
|
||||||
|
*/
|
||||||
|
private Date finishTime;
|
||||||
|
/**
|
||||||
|
* 流水线节点步骤信息
|
||||||
|
*/
|
||||||
|
private String currentNodeMsg;
|
||||||
|
/**
|
||||||
|
* 流水线节点状态
|
||||||
|
*/
|
||||||
|
private String currentNodeStatus;
|
||||||
|
/**
|
||||||
|
* 流水线实例状态
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
}
|
||||||
+12
-1
@@ -10,18 +10,29 @@ import lombok.Setter;
|
|||||||
public class PipelineNodeJobExecuteResult extends CsObject {
|
public class PipelineNodeJobExecuteResult extends CsObject {
|
||||||
private PipelineStatusEnum status;
|
private PipelineStatusEnum status;
|
||||||
private String message;
|
private String message;
|
||||||
|
private Object data;
|
||||||
|
|
||||||
public static PipelineNodeJobExecuteResult success() {
|
public static PipelineNodeJobExecuteResult success() {
|
||||||
PipelineNodeJobExecuteResult result = new PipelineNodeJobExecuteResult();
|
PipelineNodeJobExecuteResult result = new PipelineNodeJobExecuteResult();
|
||||||
result.setStatus(PipelineStatusEnum.SUCCESS);
|
result.setStatus(PipelineStatusEnum.SUCCESS);
|
||||||
result.setMessage(PipelineStatusEnum.SUCCESS.getDesc());
|
result.setMessage(PipelineStatusEnum.SUCCESS.getDesc());
|
||||||
|
result.setData("");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PipelineNodeJobExecuteResult success(String message) {
|
public static PipelineNodeJobExecuteResult success(Object data) {
|
||||||
|
PipelineNodeJobExecuteResult result = new PipelineNodeJobExecuteResult();
|
||||||
|
result.setStatus(PipelineStatusEnum.SUCCESS);
|
||||||
|
result.setMessage(PipelineStatusEnum.SUCCESS.getDesc());
|
||||||
|
result.setData(data);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PipelineNodeJobExecuteResult success(String message, Object data) {
|
||||||
PipelineNodeJobExecuteResult result = new PipelineNodeJobExecuteResult();
|
PipelineNodeJobExecuteResult result = new PipelineNodeJobExecuteResult();
|
||||||
result.setStatus(PipelineStatusEnum.SUCCESS);
|
result.setStatus(PipelineStatusEnum.SUCCESS);
|
||||||
result.setMessage(message);
|
result.setMessage(message);
|
||||||
|
result.setData(data);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-8
@@ -20,33 +20,33 @@ public class PipelineNodeTemplateVo extends CsObject {
|
|||||||
/**
|
/**
|
||||||
* 业务编码
|
* 业务编码
|
||||||
*/
|
*/
|
||||||
private String code;
|
protected String code;
|
||||||
/**
|
/**
|
||||||
* 业务类型(service:系统内置服务 rpc:远程调用)
|
* 业务类型(service:系统内置服务 rpc:远程调用)
|
||||||
*/
|
*/
|
||||||
private String type;
|
protected String type;
|
||||||
/**
|
/**
|
||||||
* 业务名称
|
* 业务名称
|
||||||
*/
|
*/
|
||||||
private String name;
|
protected String name;
|
||||||
/**
|
/**
|
||||||
* 是否可点击
|
* 是否可点击
|
||||||
*/
|
*/
|
||||||
private Boolean click = false;
|
protected Boolean click = false;
|
||||||
/**
|
/**
|
||||||
* 是否可重试
|
* 是否可重试
|
||||||
*/
|
*/
|
||||||
private Boolean retry = false;
|
protected Boolean retry = false;
|
||||||
/**
|
/**
|
||||||
* 是否可点击:点击展示详情,详情内容类型
|
* 是否可点击:点击展示详情,详情内容类型
|
||||||
*/
|
*/
|
||||||
private String detailType = "";
|
protected String detailType = "";
|
||||||
/**
|
/**
|
||||||
* 默认参数
|
* 默认参数
|
||||||
*/
|
*/
|
||||||
private Map<String, Object> parameters = new HashMap<>();
|
protected Map<String, Object> parameters = new HashMap<>();
|
||||||
/**
|
/**
|
||||||
* 流水线节点控制按钮
|
* 流水线节点控制按钮
|
||||||
*/
|
*/
|
||||||
private List<PipelineNodeOperateButtonVo> buttons = new ArrayList<>();
|
protected List<PipelineNodeOperateButtonVo> buttons = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|||||||
-34
@@ -1,34 +0,0 @@
|
|||||||
package cn.odboy.devops.job;
|
|
||||||
|
|
||||||
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
|
||||||
import cn.odboy.devops.constant.pipeline.PipelineStatusEnum;
|
|
||||||
import cn.odboy.devops.framework.pipeline.core.PipelineNodeJobExecutor;
|
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
|
||||||
import cn.odboy.devops.service.PipelineInstanceNodeDetailService;
|
|
||||||
import cn.odboy.devops.service.PipelineInstanceNodeService;
|
|
||||||
import cn.odboy.devops.service.PipelineInstanceService;
|
|
||||||
import cn.odboy.devops.service.PipelineTemplateService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.quartz.JobDataMap;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_build_java")
|
|
||||||
public class PipelineNodeBuildJava implements PipelineNodeJobExecutor {
|
|
||||||
private final PipelineTemplateService pipelineTemplateService;
|
|
||||||
private final PipelineInstanceService pipelineInstanceService;
|
|
||||||
private final PipelineInstanceNodeService pipelineInstanceNodeService;
|
|
||||||
private final PipelineInstanceNodeDetailService pipelineInstanceNodeDetailService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PipelineNodeJobExecuteResult execute(JobDataMap jobDataMap) {
|
|
||||||
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
|
||||||
String contextName = jobDataMap.getString(PipelineConst.CONTEXT_NAME);
|
|
||||||
String env = jobDataMap.getString(PipelineConst.ENV);
|
|
||||||
long templateId = jobDataMap.getLong(PipelineConst.TEMPLATE_ID);
|
|
||||||
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
|
||||||
pipelineInstanceNodeService.updatePipelineInstanceNodeByArgs(instanceId, currentNodeTemplate.getCode(), PipelineStatusEnum.SUCCESS, PipelineStatusEnum.SUCCESS.getDesc());
|
|
||||||
return PipelineNodeJobExecuteResult.success();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
package cn.odboy.devops.job;
|
||||||
|
|
||||||
|
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
|
import cn.odboy.devops.framework.pipeline.AbstractPipelineNodeJobService;
|
||||||
|
import cn.odboy.devops.framework.pipeline.core.PipelineNodeJobExecutor;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
|
import cn.odboy.devops.job.biz.PipelineNodeBuildJavaBiz;
|
||||||
|
import cn.odboy.devops.job.biz.PipelineNodeInitBiz;
|
||||||
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.quartz.JobDataMap;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_build_java")
|
||||||
|
public class PipelineNodeBuildJavaJob extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
||||||
|
private final PipelineNodeBuildJavaBiz pipelineNodeBuildJavaBiz;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PipelineNodeJobExecuteResult execute(JobDataMap jobDataMap) throws BadRequestException {
|
||||||
|
// 参数列表
|
||||||
|
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
||||||
|
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
||||||
|
PipelineInstanceNodeTb pipelineInstanceNode = getCurrentNodeInfo(instanceId, currentNodeTemplate.getCode());
|
||||||
|
String contextName = jobDataMap.getString(PipelineConst.CONTEXT_NAME);
|
||||||
|
String env = jobDataMap.getString(PipelineConst.ENV);
|
||||||
|
List<PipelineNodeTemplateVo> templateList = JSON.parseArray(jobDataMap.getString(PipelineConst.TEMPLATE), PipelineNodeTemplateVo.class);
|
||||||
|
PipelineNodeJobExecuteResult lastNodeResult = (PipelineNodeJobExecuteResult) jobDataMap.get(PipelineConst.LAST_NODE_RESULT);
|
||||||
|
// 步骤执行
|
||||||
|
pipelineNodeBuildJavaBiz.initStart(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
pipelineNodeBuildJavaBiz.createReleaseBranch(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
pipelineNodeBuildJavaBiz.mergeMasterToRelease(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
pipelineNodeBuildJavaBiz.initFinish(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
return PipelineNodeJobExecuteResult.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
-34
@@ -1,34 +0,0 @@
|
|||||||
package cn.odboy.devops.job;
|
|
||||||
|
|
||||||
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
|
||||||
import cn.odboy.devops.constant.pipeline.PipelineStatusEnum;
|
|
||||||
import cn.odboy.devops.framework.pipeline.core.PipelineNodeJobExecutor;
|
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
|
||||||
import cn.odboy.devops.service.PipelineInstanceNodeDetailService;
|
|
||||||
import cn.odboy.devops.service.PipelineInstanceNodeService;
|
|
||||||
import cn.odboy.devops.service.PipelineInstanceService;
|
|
||||||
import cn.odboy.devops.service.PipelineTemplateService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.quartz.JobDataMap;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_deploy_java")
|
|
||||||
public class PipelineNodeDeployJava implements PipelineNodeJobExecutor {
|
|
||||||
private final PipelineTemplateService pipelineTemplateService;
|
|
||||||
private final PipelineInstanceService pipelineInstanceService;
|
|
||||||
private final PipelineInstanceNodeService pipelineInstanceNodeService;
|
|
||||||
private final PipelineInstanceNodeDetailService pipelineInstanceNodeDetailService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PipelineNodeJobExecuteResult execute(JobDataMap jobDataMap) {
|
|
||||||
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
|
||||||
String contextName = jobDataMap.getString(PipelineConst.CONTEXT_NAME);
|
|
||||||
String env = jobDataMap.getString(PipelineConst.ENV);
|
|
||||||
long templateId = jobDataMap.getLong(PipelineConst.TEMPLATE_ID);
|
|
||||||
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
|
||||||
pipelineInstanceNodeService.updatePipelineInstanceNodeByArgs(instanceId, currentNodeTemplate.getCode(), PipelineStatusEnum.SUCCESS, PipelineStatusEnum.SUCCESS.getDesc());
|
|
||||||
return PipelineNodeJobExecuteResult.success();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
package cn.odboy.devops.job;
|
||||||
|
|
||||||
|
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
|
import cn.odboy.devops.framework.pipeline.AbstractPipelineNodeJobService;
|
||||||
|
import cn.odboy.devops.framework.pipeline.core.PipelineNodeJobExecutor;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
|
import cn.odboy.devops.job.biz.PipelineNodeBuildJavaBiz;
|
||||||
|
import cn.odboy.devops.job.biz.PipelineNodeDeployJavaBiz;
|
||||||
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.quartz.JobDataMap;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_deploy_java")
|
||||||
|
public class PipelineNodeDeployJavaJob extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
||||||
|
private final PipelineNodeDeployJavaBiz pipelineNodeDeployJavaBiz;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PipelineNodeJobExecuteResult execute(JobDataMap jobDataMap) throws BadRequestException {
|
||||||
|
// 参数列表
|
||||||
|
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
||||||
|
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
||||||
|
PipelineInstanceNodeTb pipelineInstanceNode = getCurrentNodeInfo(instanceId, currentNodeTemplate.getCode());
|
||||||
|
String contextName = jobDataMap.getString(PipelineConst.CONTEXT_NAME);
|
||||||
|
String env = jobDataMap.getString(PipelineConst.ENV);
|
||||||
|
List<PipelineNodeTemplateVo> templateList = JSON.parseArray(jobDataMap.getString(PipelineConst.TEMPLATE), PipelineNodeTemplateVo.class);
|
||||||
|
PipelineNodeJobExecuteResult lastNodeResult = (PipelineNodeJobExecuteResult) jobDataMap.get(PipelineConst.LAST_NODE_RESULT);
|
||||||
|
// 步骤执行
|
||||||
|
pipelineNodeDeployJavaBiz.initStart(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
pipelineNodeDeployJavaBiz.createReleaseBranch(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
pipelineNodeDeployJavaBiz.mergeMasterToRelease(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
pipelineNodeDeployJavaBiz.initFinish(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
return PipelineNodeJobExecuteResult.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
+23
-15
@@ -1,34 +1,42 @@
|
|||||||
package cn.odboy.devops.job;
|
package cn.odboy.devops.job;
|
||||||
|
|
||||||
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
||||||
import cn.odboy.devops.constant.pipeline.PipelineStatusEnum;
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
|
import cn.odboy.devops.framework.pipeline.AbstractPipelineNodeJobService;
|
||||||
import cn.odboy.devops.framework.pipeline.core.PipelineNodeJobExecutor;
|
import cn.odboy.devops.framework.pipeline.core.PipelineNodeJobExecutor;
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
import cn.odboy.devops.service.PipelineInstanceNodeDetailService;
|
import cn.odboy.devops.job.biz.PipelineNodeInitBiz;
|
||||||
import cn.odboy.devops.service.PipelineInstanceNodeService;
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
import cn.odboy.devops.service.PipelineInstanceService;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import cn.odboy.devops.service.PipelineTemplateService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.quartz.JobDataMap;
|
import org.quartz.JobDataMap;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_init")
|
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_init")
|
||||||
public class PipelineNodeInitJob implements PipelineNodeJobExecutor {
|
@RequiredArgsConstructor
|
||||||
private final PipelineTemplateService pipelineTemplateService;
|
public class PipelineNodeInitJob extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
||||||
private final PipelineInstanceService pipelineInstanceService;
|
private final PipelineNodeInitBiz pipelineNodeInitBiz;
|
||||||
private final PipelineInstanceNodeService pipelineInstanceNodeService;
|
|
||||||
private final PipelineInstanceNodeDetailService pipelineInstanceNodeDetailService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PipelineNodeJobExecuteResult execute(JobDataMap jobDataMap) {
|
public PipelineNodeJobExecuteResult execute(JobDataMap jobDataMap) throws BadRequestException {
|
||||||
|
// 参数列表
|
||||||
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
||||||
|
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
||||||
|
PipelineInstanceNodeTb pipelineInstanceNode = getCurrentNodeInfo(instanceId, currentNodeTemplate.getCode());
|
||||||
String contextName = jobDataMap.getString(PipelineConst.CONTEXT_NAME);
|
String contextName = jobDataMap.getString(PipelineConst.CONTEXT_NAME);
|
||||||
String env = jobDataMap.getString(PipelineConst.ENV);
|
String env = jobDataMap.getString(PipelineConst.ENV);
|
||||||
long templateId = jobDataMap.getLong(PipelineConst.TEMPLATE_ID);
|
List<PipelineNodeTemplateVo> templateList = JSON.parseArray(jobDataMap.getString(PipelineConst.TEMPLATE), PipelineNodeTemplateVo.class);
|
||||||
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
PipelineNodeJobExecuteResult lastNodeResult = (PipelineNodeJobExecuteResult) jobDataMap.get(PipelineConst.LAST_NODE_RESULT);
|
||||||
pipelineInstanceNodeService.updatePipelineInstanceNodeByArgs(instanceId, currentNodeTemplate.getCode(), PipelineStatusEnum.SUCCESS, PipelineStatusEnum.SUCCESS.getDesc());
|
// 步骤执行
|
||||||
|
pipelineNodeInitBiz.initStart(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
pipelineNodeInitBiz.createReleaseBranch(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
pipelineNodeInitBiz.mergeMasterToRelease(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
pipelineNodeInitBiz.initFinish(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
return PipelineNodeJobExecuteResult.success();
|
return PipelineNodeJobExecuteResult.success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-34
@@ -1,34 +0,0 @@
|
|||||||
package cn.odboy.devops.job;
|
|
||||||
|
|
||||||
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
|
||||||
import cn.odboy.devops.constant.pipeline.PipelineStatusEnum;
|
|
||||||
import cn.odboy.devops.framework.pipeline.core.PipelineNodeJobExecutor;
|
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
|
||||||
import cn.odboy.devops.service.PipelineInstanceNodeDetailService;
|
|
||||||
import cn.odboy.devops.service.PipelineInstanceNodeService;
|
|
||||||
import cn.odboy.devops.service.PipelineInstanceService;
|
|
||||||
import cn.odboy.devops.service.PipelineTemplateService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.quartz.JobDataMap;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_merge_branch")
|
|
||||||
public class PipelineNodeMergeBranch implements PipelineNodeJobExecutor {
|
|
||||||
private final PipelineTemplateService pipelineTemplateService;
|
|
||||||
private final PipelineInstanceService pipelineInstanceService;
|
|
||||||
private final PipelineInstanceNodeService pipelineInstanceNodeService;
|
|
||||||
private final PipelineInstanceNodeDetailService pipelineInstanceNodeDetailService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PipelineNodeJobExecuteResult execute(JobDataMap jobDataMap) {
|
|
||||||
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
|
||||||
String contextName = jobDataMap.getString(PipelineConst.CONTEXT_NAME);
|
|
||||||
String env = jobDataMap.getString(PipelineConst.ENV);
|
|
||||||
long templateId = jobDataMap.getLong(PipelineConst.TEMPLATE_ID);
|
|
||||||
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
|
||||||
pipelineInstanceNodeService.updatePipelineInstanceNodeByArgs(instanceId, currentNodeTemplate.getCode(), PipelineStatusEnum.SUCCESS, PipelineStatusEnum.SUCCESS.getDesc());
|
|
||||||
return PipelineNodeJobExecuteResult.success();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
package cn.odboy.devops.job;
|
||||||
|
|
||||||
|
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
|
import cn.odboy.devops.framework.pipeline.AbstractPipelineNodeJobService;
|
||||||
|
import cn.odboy.devops.framework.pipeline.core.PipelineNodeJobExecutor;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
|
import cn.odboy.devops.job.biz.PipelineNodeInitBiz;
|
||||||
|
import cn.odboy.devops.job.biz.PipelineNodeMergeBranchBiz;
|
||||||
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.quartz.JobDataMap;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_merge_branch")
|
||||||
|
public class PipelineNodeMergeBranchJob extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
||||||
|
private final PipelineNodeMergeBranchBiz pipelineNodeMergeBranchBiz;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PipelineNodeJobExecuteResult execute(JobDataMap jobDataMap) throws BadRequestException {
|
||||||
|
// 参数列表
|
||||||
|
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
||||||
|
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
||||||
|
PipelineInstanceNodeTb pipelineInstanceNode = getCurrentNodeInfo(instanceId, currentNodeTemplate.getCode());
|
||||||
|
String contextName = jobDataMap.getString(PipelineConst.CONTEXT_NAME);
|
||||||
|
String env = jobDataMap.getString(PipelineConst.ENV);
|
||||||
|
List<PipelineNodeTemplateVo> templateList = JSON.parseArray(jobDataMap.getString(PipelineConst.TEMPLATE), PipelineNodeTemplateVo.class);
|
||||||
|
PipelineNodeJobExecuteResult lastNodeResult = (PipelineNodeJobExecuteResult) jobDataMap.get(PipelineConst.LAST_NODE_RESULT);
|
||||||
|
// 步骤执行
|
||||||
|
pipelineNodeMergeBranchBiz.initStart(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
pipelineNodeMergeBranchBiz.createReleaseBranch(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
pipelineNodeMergeBranchBiz.mergeMasterToRelease(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
pipelineNodeMergeBranchBiz.initFinish(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
return PipelineNodeJobExecuteResult.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
package cn.odboy.devops.job.biz;
|
||||||
|
|
||||||
|
import cn.hutool.core.thread.ThreadUtil;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
|
import cn.odboy.devops.framework.pipeline.log.PipelineNodeStepLog;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class PipelineNodeBuildJavaBiz {
|
||||||
|
@PipelineNodeStepLog("初始化开始")
|
||||||
|
public void initStart(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PipelineNodeStepLog("Master分支合并到Release分支")
|
||||||
|
public void mergeMasterToRelease(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PipelineNodeStepLog("新建Release分支")
|
||||||
|
public void createReleaseBranch(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PipelineNodeStepLog("初始化完成")
|
||||||
|
public void initFinish(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
package cn.odboy.devops.job.biz;
|
||||||
|
|
||||||
|
import cn.hutool.core.thread.ThreadUtil;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
|
import cn.odboy.devops.framework.pipeline.log.PipelineNodeStepLog;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class PipelineNodeDeployJavaBiz {
|
||||||
|
@PipelineNodeStepLog("初始化开始")
|
||||||
|
public void initStart(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PipelineNodeStepLog("Master分支合并到Release分支")
|
||||||
|
public void mergeMasterToRelease(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PipelineNodeStepLog("新建Release分支")
|
||||||
|
public void createReleaseBranch(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PipelineNodeStepLog("初始化完成")
|
||||||
|
public void initFinish(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
package cn.odboy.devops.job.biz;
|
||||||
|
|
||||||
|
import cn.hutool.core.thread.ThreadUtil;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
|
import cn.odboy.devops.framework.pipeline.log.PipelineNodeStepLog;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class PipelineNodeInitBiz {
|
||||||
|
@PipelineNodeStepLog("初始化开始")
|
||||||
|
public void initStart(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PipelineNodeStepLog("Master分支合并到Release分支")
|
||||||
|
public void mergeMasterToRelease(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PipelineNodeStepLog("新建Release分支")
|
||||||
|
public void createReleaseBranch(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PipelineNodeStepLog("初始化完成")
|
||||||
|
public void initFinish(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
package cn.odboy.devops.job.biz;
|
||||||
|
|
||||||
|
import cn.hutool.core.thread.ThreadUtil;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
|
import cn.odboy.devops.framework.pipeline.log.PipelineNodeStepLog;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class PipelineNodeMergeBranchBiz {
|
||||||
|
@PipelineNodeStepLog("初始化开始")
|
||||||
|
public void initStart(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PipelineNodeStepLog("Master分支合并到Release分支")
|
||||||
|
public void mergeMasterToRelease(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PipelineNodeStepLog("新建Release分支")
|
||||||
|
public void createReleaseBranch(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PipelineNodeStepLog("初始化完成")
|
||||||
|
public void initFinish(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
|
ThreadUtil.safeSleep(5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
@@ -1,8 +1,13 @@
|
|||||||
package cn.odboy.devops.service;
|
package cn.odboy.devops.service;
|
||||||
|
|
||||||
|
import cn.odboy.devops.constant.pipeline.PipelineStatusEnum;
|
||||||
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeDetailTb;
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeDetailTb;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
import com.anwen.mongo.service.IService;
|
import com.anwen.mongo.service.IService;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* 流水线实例节点明细
|
* 流水线实例节点明细
|
||||||
@@ -12,5 +17,11 @@ import com.anwen.mongo.service.IService;
|
|||||||
* @since 2025-06-26
|
* @since 2025-06-26
|
||||||
*/
|
*/
|
||||||
public interface PipelineInstanceNodeDetailService extends IService<PipelineInstanceNodeDetailTb> {
|
public interface PipelineInstanceNodeDetailService extends IService<PipelineInstanceNodeDetailTb> {
|
||||||
|
void addLog(Long nodeId, String nodeCode, String stepName, PipelineStatusEnum status, String stepMsg, Date finishTime);
|
||||||
|
|
||||||
|
PipelineInstanceNodeDetailTb getPipelineInstanceNodeDetailByArgs(Long nodeId, String nodeCode, String stepName);
|
||||||
|
|
||||||
|
void removeByNodeIds(List<Long> nodeIds);
|
||||||
|
|
||||||
|
PipelineInstanceNodeDetailTb getLastPipelineInstanceNodeDetailByArgs(PipelineInstanceNodeTb instanceNode, Long nodeId, String nodeCode);
|
||||||
}
|
}
|
||||||
|
|||||||
+11
@@ -5,6 +5,9 @@ import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
|||||||
import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
||||||
import com.anwen.mongo.service.IService;
|
import com.anwen.mongo.service.IService;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流水线实例节点明细
|
* 流水线实例节点明细
|
||||||
*
|
*
|
||||||
@@ -13,6 +16,14 @@ import com.anwen.mongo.service.IService;
|
|||||||
*/
|
*/
|
||||||
public interface PipelineInstanceNodeService extends IService<PipelineInstanceNodeTb> {
|
public interface PipelineInstanceNodeService extends IService<PipelineInstanceNodeTb> {
|
||||||
void createPipelineInstanceDetail(PipelineInstanceTb pipelineInstanceTb);
|
void createPipelineInstanceDetail(PipelineInstanceTb pipelineInstanceTb);
|
||||||
|
|
||||||
void updatePipelineInstanceNodeByArgs(Long instanceId, String code, PipelineStatusEnum pipelineStatusEnum, String msg);
|
void updatePipelineInstanceNodeByArgs(Long instanceId, String code, PipelineStatusEnum pipelineStatusEnum, String msg);
|
||||||
|
|
||||||
PipelineInstanceNodeTb getPipelineInstanceNodeByArgs(Long instanceId, String code);
|
PipelineInstanceNodeTb getPipelineInstanceNodeByArgs(Long instanceId, String code);
|
||||||
|
|
||||||
|
void remakePipelineInstanceDetail(PipelineInstanceTb pipelineInstanceTb, String retryNodeCode);
|
||||||
|
|
||||||
|
List<PipelineInstanceNodeTb> queryPipelineInstanceNodeListByInstanceId(Long instanceId);
|
||||||
|
|
||||||
|
void finishPipelineInstanceNodeByArgs(Long instanceId, String nodeCode, PipelineStatusEnum pipelineStatusEnum, String desc, Date date);
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -1,6 +1,9 @@
|
|||||||
package cn.odboy.devops.service;
|
package cn.odboy.devops.service;
|
||||||
|
|
||||||
import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeDataVo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@@ -11,5 +14,7 @@ import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
|||||||
* @since 2025-06-26
|
* @since 2025-06-26
|
||||||
*/
|
*/
|
||||||
public interface PipelineInstanceService {
|
public interface PipelineInstanceService {
|
||||||
void start(PipelineInstanceTb pipelineInstanceTb);
|
String startPipeline(PipelineInstanceTb pipelineInstanceTb);
|
||||||
|
void restartPipeline(PipelineInstanceTb pipelineInstanceTb, String retryNodeCode);
|
||||||
|
List<PipelineNodeDataVo> queryLastPipelineDetail(String instanceId);
|
||||||
}
|
}
|
||||||
|
|||||||
+54
-6
@@ -1,31 +1,36 @@
|
|||||||
package cn.odboy.devops.service.impl;
|
package cn.odboy.devops.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.odboy.devops.constant.pipeline.PipelineStatusEnum;
|
import cn.odboy.devops.constant.pipeline.PipelineStatusEnum;
|
||||||
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeDetailTb;
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeDetailTb;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
import cn.odboy.devops.service.PipelineInstanceNodeDetailService;
|
import cn.odboy.devops.service.PipelineInstanceNodeDetailService;
|
||||||
import com.anwen.mongo.conditions.query.LambdaQueryChainWrapper;
|
import com.anwen.mongo.conditions.query.LambdaQueryChainWrapper;
|
||||||
|
import com.anwen.mongo.conditions.update.LambdaUpdateChainWrapper;
|
||||||
import com.anwen.mongo.service.impl.ServiceImpl;
|
import com.anwen.mongo.service.impl.ServiceImpl;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class PipelineInstanceNodeDetailServiceImpl extends ServiceImpl<PipelineInstanceNodeDetailTb> implements PipelineInstanceNodeDetailService {
|
public class PipelineInstanceNodeDetailServiceImpl extends ServiceImpl<PipelineInstanceNodeDetailTb> implements PipelineInstanceNodeDetailService {
|
||||||
|
|
||||||
public void addLog(String nodeId, Integer nodeIndex, String nodeCode, String stepName, PipelineStatusEnum status, String stepMsg) {
|
@Override
|
||||||
|
public void addLog(Long nodeId, String nodeCode, String stepName, PipelineStatusEnum status, String stepMsg, Date finishTime) {
|
||||||
PipelineInstanceNodeDetailTb record = getPipelineInstanceNodeDetailByArgs(nodeId, nodeCode, stepName);
|
PipelineInstanceNodeDetailTb record = getPipelineInstanceNodeDetailByArgs(nodeId, nodeCode, stepName);
|
||||||
if (record != null) {
|
if (record != null) {
|
||||||
record.setStepStatus(status.getCode());
|
record.setStepStatus(status.getCode());
|
||||||
record.setStepMsg(stepMsg);
|
record.setStepMsg(stepMsg);
|
||||||
|
record.setFinishTime(finishTime);
|
||||||
updateById(record);
|
updateById(record);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
record = new PipelineInstanceNodeDetailTb();
|
record = new PipelineInstanceNodeDetailTb();
|
||||||
record.setNodeId(nodeId);
|
record.setNodeId(nodeId);
|
||||||
record.setStartTime(new Date());
|
record.setStartTime(new Date());
|
||||||
record.setNodeIndex(nodeIndex);
|
|
||||||
record.setNodeCode(nodeCode);
|
record.setNodeCode(nodeCode);
|
||||||
record.setStepName(stepName);
|
record.setStepName(stepName);
|
||||||
record.setStepStatus(status.getCode());
|
record.setStepStatus(status.getCode());
|
||||||
@@ -33,10 +38,53 @@ public class PipelineInstanceNodeDetailServiceImpl extends ServiceImpl<PipelineI
|
|||||||
save(record);
|
save(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PipelineInstanceNodeDetailTb getPipelineInstanceNodeDetailByArgs(String nodeId, String nodeCode, String stepName) {
|
@Override
|
||||||
return one(new LambdaQueryChainWrapper<>(getBaseMapper(), PipelineInstanceNodeDetailTb.class)
|
public PipelineInstanceNodeDetailTb getPipelineInstanceNodeDetailByArgs(Long nodeId, String nodeCode, String stepName) {
|
||||||
.eq(PipelineInstanceNodeDetailTb::getNodeId, nodeId).eq(PipelineInstanceNodeDetailTb::getNodeCode, nodeCode)
|
return one(new LambdaQueryChainWrapper<>(getBaseMapper(), PipelineInstanceNodeDetailTb.class).eq(PipelineInstanceNodeDetailTb::getNodeId, nodeId).eq(PipelineInstanceNodeDetailTb::getNodeCode, nodeCode).eq(PipelineInstanceNodeDetailTb::getStepName, stepName));
|
||||||
.eq(PipelineInstanceNodeDetailTb::getStepName, stepName)
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeByNodeIds(List<Long> nodeIds) {
|
||||||
|
if (CollUtil.isNotEmpty(nodeIds)) {
|
||||||
|
remove(new LambdaUpdateChainWrapper<>(getBaseMapper(), PipelineInstanceNodeDetailTb.class).in(PipelineInstanceNodeDetailTb::getNodeId, nodeIds));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PipelineInstanceNodeDetailTb getLastPipelineInstanceNodeDetailByArgs(PipelineInstanceNodeTb instanceNode, Long nodeId, String nodeCode) {
|
||||||
|
List<PipelineInstanceNodeDetailTb> pipelineInstanceNodeDetailList = list(new LambdaQueryChainWrapper<>(getBaseMapper(), PipelineInstanceNodeDetailTb.class)
|
||||||
|
.eq(PipelineInstanceNodeDetailTb::getNodeId, nodeId)
|
||||||
|
.eq(PipelineInstanceNodeDetailTb::getNodeCode, nodeCode)
|
||||||
|
.orderByDesc(PipelineInstanceNodeDetailTb::getId)
|
||||||
);
|
);
|
||||||
|
// 明细为空,返回节点状态
|
||||||
|
if (pipelineInstanceNodeDetailList.isEmpty()) {
|
||||||
|
PipelineInstanceNodeDetailTb pipelineInstanceNodeDetailTb = new PipelineInstanceNodeDetailTb();
|
||||||
|
pipelineInstanceNodeDetailTb.setStepMsg(instanceNode.getCurrentNodeMsg());
|
||||||
|
pipelineInstanceNodeDetailTb.setStepStatus(instanceNode.getCurrentNodeStatus());
|
||||||
|
return pipelineInstanceNodeDetailTb;
|
||||||
|
}
|
||||||
|
boolean existFail = pipelineInstanceNodeDetailList.stream().anyMatch(f -> PipelineStatusEnum.FAIL.getCode().equals(f.getStepStatus()));
|
||||||
|
// 节点中存在失败的步骤
|
||||||
|
if (existFail) {
|
||||||
|
PipelineInstanceNodeDetailTb pipelineInstanceNodeDetailTb = new PipelineInstanceNodeDetailTb();
|
||||||
|
pipelineInstanceNodeDetailTb.setStepMsg(instanceNode.getCurrentNodeMsg());
|
||||||
|
pipelineInstanceNodeDetailTb.setStepStatus(instanceNode.getCurrentNodeStatus());
|
||||||
|
return pipelineInstanceNodeDetailTb;
|
||||||
|
}
|
||||||
|
// 节点中所有步骤都成功
|
||||||
|
long totalStep = pipelineInstanceNodeDetailList.size();
|
||||||
|
long totalSuccessStep = pipelineInstanceNodeDetailList.stream().filter(f -> PipelineStatusEnum.SUCCESS.getCode().equals(f.getStepStatus())).count();
|
||||||
|
if (totalSuccessStep == totalStep) {
|
||||||
|
PipelineInstanceNodeDetailTb pipelineInstanceNodeDetailTb = new PipelineInstanceNodeDetailTb();
|
||||||
|
pipelineInstanceNodeDetailTb.setStepMsg(instanceNode.getCurrentNodeMsg());
|
||||||
|
pipelineInstanceNodeDetailTb.setStepStatus(instanceNode.getCurrentNodeStatus());
|
||||||
|
return pipelineInstanceNodeDetailTb;
|
||||||
|
}
|
||||||
|
// 返回节点步骤状态
|
||||||
|
PipelineInstanceNodeDetailTb pipelineInstanceNodeDetailTb = pipelineInstanceNodeDetailList.get(0);
|
||||||
|
// 返回步骤说明
|
||||||
|
pipelineInstanceNodeDetailTb.setStepMsg(pipelineInstanceNodeDetailTb.getStepName());
|
||||||
|
return pipelineInstanceNodeDetailTb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+59
@@ -5,20 +5,26 @@ import cn.odboy.devops.constant.pipeline.PipelineStatusEnum;
|
|||||||
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
|
import cn.odboy.devops.service.PipelineInstanceNodeDetailService;
|
||||||
import cn.odboy.devops.service.PipelineInstanceNodeService;
|
import cn.odboy.devops.service.PipelineInstanceNodeService;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.anwen.mongo.conditions.query.LambdaQueryChainWrapper;
|
import com.anwen.mongo.conditions.query.LambdaQueryChainWrapper;
|
||||||
import com.anwen.mongo.service.impl.ServiceImpl;
|
import com.anwen.mongo.service.impl.ServiceImpl;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class PipelineInstanceNodeServiceImpl extends ServiceImpl<PipelineInstanceNodeTb> implements PipelineInstanceNodeService {
|
public class PipelineInstanceNodeServiceImpl extends ServiceImpl<PipelineInstanceNodeTb> implements PipelineInstanceNodeService {
|
||||||
|
private final PipelineInstanceNodeDetailService pipelineInstanceNodeDetailService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createPipelineInstanceDetail(PipelineInstanceTb pipelineInstanceTb) {
|
public void createPipelineInstanceDetail(PipelineInstanceTb pipelineInstanceTb) {
|
||||||
String templateContent = pipelineInstanceTb.getTemplateContent();
|
String templateContent = pipelineInstanceTb.getTemplateContent();
|
||||||
@@ -36,6 +42,8 @@ public class PipelineInstanceNodeServiceImpl extends ServiceImpl<PipelineInstanc
|
|||||||
record.setClick(pipelineNodeTemplateVo.getClick());
|
record.setClick(pipelineNodeTemplateVo.getClick());
|
||||||
record.setRetry(pipelineNodeTemplateVo.getRetry());
|
record.setRetry(pipelineNodeTemplateVo.getRetry());
|
||||||
record.setButtons(pipelineNodeTemplateVo.getButtons());
|
record.setButtons(pipelineNodeTemplateVo.getButtons());
|
||||||
|
record.setCurrentNodeStatus(PipelineStatusEnum.PENDING.getCode());
|
||||||
|
record.setCurrentNodeMsg(PipelineStatusEnum.PENDING.getDesc());
|
||||||
records.add(record);
|
records.add(record);
|
||||||
}
|
}
|
||||||
saveBatch(records);
|
saveBatch(records);
|
||||||
@@ -57,4 +65,55 @@ public class PipelineInstanceNodeServiceImpl extends ServiceImpl<PipelineInstanc
|
|||||||
.eq(PipelineInstanceNodeTb::getCode, code)
|
.eq(PipelineInstanceNodeTb::getCode, code)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remakePipelineInstanceDetail(PipelineInstanceTb pipelineInstanceTb, String retryNodeCode) {
|
||||||
|
List<String> penddingNodeList = new ArrayList<>();
|
||||||
|
List<PipelineNodeTemplateVo> pipelineNodeTemplateVos = JSON.parseArray(pipelineInstanceTb.getTemplateContent(), PipelineNodeTemplateVo.class);
|
||||||
|
boolean findFlag = false;
|
||||||
|
for (PipelineNodeTemplateVo pipelineNodeTemplateVo : pipelineNodeTemplateVos) {
|
||||||
|
if (pipelineNodeTemplateVo.getCode().equals(retryNodeCode) || findFlag) {
|
||||||
|
findFlag = true;
|
||||||
|
penddingNodeList.add(pipelineNodeTemplateVo.getCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 更新节点状态
|
||||||
|
List<PipelineInstanceNodeTb> instanceNodeList = list(new LambdaQueryChainWrapper<>(getBaseMapper(), PipelineInstanceNodeTb.class)
|
||||||
|
.eq(PipelineInstanceNodeTb::getInstanceId, pipelineInstanceTb.getInstanceId())
|
||||||
|
.eq(PipelineInstanceNodeTb::getCode, penddingNodeList)
|
||||||
|
);
|
||||||
|
if (CollUtil.isNotEmpty(instanceNodeList)) {
|
||||||
|
Date nowTime = new Date();
|
||||||
|
for (PipelineInstanceNodeTb pipelineInstanceNodeTb : instanceNodeList) {
|
||||||
|
pipelineInstanceNodeTb.setUpdateTime(nowTime);
|
||||||
|
pipelineInstanceNodeTb.setStartTime(null);
|
||||||
|
pipelineInstanceNodeTb.setCurrentNodeMsg(PipelineStatusEnum.PENDING.getDesc());
|
||||||
|
pipelineInstanceNodeTb.setCurrentNodeStatus(PipelineStatusEnum.PENDING.getCode());
|
||||||
|
}
|
||||||
|
updateBatchByIds(instanceNodeList);
|
||||||
|
// 删除节点明细数据
|
||||||
|
List<Long> nodeIds = instanceNodeList.stream()
|
||||||
|
.map(PipelineInstanceNodeTb::getId)
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
pipelineInstanceNodeDetailService.removeByNodeIds(nodeIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PipelineInstanceNodeTb> queryPipelineInstanceNodeListByInstanceId(Long instanceId) {
|
||||||
|
return list(new LambdaQueryChainWrapper<>(getBaseMapper(), PipelineInstanceNodeTb.class)
|
||||||
|
.eq(PipelineInstanceNodeTb::getInstanceId, instanceId)
|
||||||
|
.orderByAsc(PipelineInstanceNodeTb::getId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finishPipelineInstanceNodeByArgs(Long instanceId, String nodeCode, PipelineStatusEnum pipelineStatusEnum, String desc, Date date) {
|
||||||
|
PipelineInstanceNodeTb pipelineInstanceNode = getPipelineInstanceNodeByArgs(instanceId, nodeCode);
|
||||||
|
pipelineInstanceNode.setCurrentNodeStatus(pipelineStatusEnum.getCode());
|
||||||
|
pipelineInstanceNode.setCurrentNodeMsg(desc);
|
||||||
|
pipelineInstanceNode.setFinishTime(date);
|
||||||
|
updateById(pipelineInstanceNode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+50
-74
@@ -1,14 +1,15 @@
|
|||||||
package cn.odboy.devops.service.impl;
|
package cn.odboy.devops.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.thread.ThreadUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.util.IdUtil;
|
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
||||||
import cn.odboy.devops.constant.pipeline.PipelineStatusEnum;
|
import cn.odboy.devops.constant.pipeline.PipelineStatusEnum;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeDetailTb;
|
||||||
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
||||||
import cn.odboy.devops.dal.mysql.PipelineInstanceMapper;
|
import cn.odboy.devops.dal.mysql.PipelineInstanceMapper;
|
||||||
import cn.odboy.devops.dal.redis.PipelineInstanceDAO;
|
import cn.odboy.devops.dal.redis.PipelineInstanceDAO;
|
||||||
import cn.odboy.devops.framework.pipeline.core.PipelineJobManage;
|
import cn.odboy.devops.framework.pipeline.core.PipelineJobManage;
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeDataVo;
|
||||||
import cn.odboy.devops.service.PipelineInstanceNodeDetailService;
|
import cn.odboy.devops.service.PipelineInstanceNodeDetailService;
|
||||||
import cn.odboy.devops.service.PipelineInstanceNodeService;
|
import cn.odboy.devops.service.PipelineInstanceNodeService;
|
||||||
import cn.odboy.devops.service.PipelineInstanceService;
|
import cn.odboy.devops.service.PipelineInstanceService;
|
||||||
@@ -18,6 +19,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -26,89 +28,63 @@ import java.util.List;
|
|||||||
public class PipelineInstanceServiceImpl implements PipelineInstanceService {
|
public class PipelineInstanceServiceImpl implements PipelineInstanceService {
|
||||||
private final PipelineJobManage pipelineJobManage;
|
private final PipelineJobManage pipelineJobManage;
|
||||||
private final PipelineInstanceMapper pipelineInstanceMapper;
|
private final PipelineInstanceMapper pipelineInstanceMapper;
|
||||||
|
private final PipelineInstanceDAO pipelineInstanceDAO;
|
||||||
private final PipelineInstanceNodeService pipelineInstanceNodeService;
|
private final PipelineInstanceNodeService pipelineInstanceNodeService;
|
||||||
private final PipelineInstanceNodeDetailService pipelineInstanceNodeDetailService;
|
private final PipelineInstanceNodeDetailService pipelineInstanceNodeDetailService;
|
||||||
private final PipelineInstanceDAO pipelineInstanceDAO;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(PipelineInstanceTb pipelineInstanceTb) {
|
public String startPipeline(PipelineInstanceTb pipelineInstanceTb) {
|
||||||
if (pipelineInstanceDAO.lock(pipelineInstanceTb)) {
|
if (pipelineInstanceDAO.lock(pipelineInstanceTb)) {
|
||||||
throw new BadRequestException("流水线运行中,无法重复执行");
|
throw new BadRequestException("流水线运行中,无法重复执行");
|
||||||
}
|
}
|
||||||
ThreadUtil.execAsync(() -> innerStart(pipelineInstanceTb));
|
return PipelineConst.INSTANCE_ID + pipelineJobManage.startJob(pipelineInstanceTb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void innerStart(PipelineInstanceTb pipelineInstanceTb) {
|
@Override
|
||||||
// 雪花id
|
public void restartPipeline(PipelineInstanceTb pipelineInstanceTb, String retryNodeCode) {
|
||||||
pipelineInstanceTb.setInstanceId(IdUtil.getSnowflakeNextId());
|
if (pipelineInstanceTb.getInstanceId() == null) {
|
||||||
pipelineInstanceTb.setStatus(PipelineStatusEnum.PENDING.getCode());
|
throw new BadRequestException("流水线实例Id必填");
|
||||||
// 创建实例
|
|
||||||
pipelineInstanceMapper.insert(pipelineInstanceTb);
|
|
||||||
// 创建实例明细
|
|
||||||
pipelineInstanceNodeService.createPipelineInstanceDetail(pipelineInstanceTb);
|
|
||||||
// 流水线节点模板
|
|
||||||
String templateContent = pipelineInstanceTb.getTemplateContent();
|
|
||||||
List<PipelineNodeTemplateVo> pipelineNodeTemplateVos = JSON.parseArray(templateContent, PipelineNodeTemplateVo.class);
|
|
||||||
Long instanceId = pipelineInstanceTb.getInstanceId();
|
|
||||||
// 流水线实例状态(默认是成功的)
|
|
||||||
PipelineStatusEnum pipelineStatusEnum = PipelineStatusEnum.SUCCESS;
|
|
||||||
try {
|
|
||||||
pipelineInstanceTb.setStatus(PipelineStatusEnum.RUNNING.getCode());
|
|
||||||
pipelineInstanceMapper.updateById(pipelineInstanceTb);
|
|
||||||
// 依次执行流水线节点任务
|
|
||||||
for (PipelineNodeTemplateVo pipelineNodeTemplateVo : pipelineNodeTemplateVos) {
|
|
||||||
try {
|
|
||||||
pipelineJobManage.startJob(pipelineInstanceTb, pipelineNodeTemplateVo);
|
|
||||||
pipelineInstanceTb.setCurrentNode(pipelineNodeTemplateVo.getCode());
|
|
||||||
pipelineInstanceTb.setCurrentNodeStatus(PipelineStatusEnum.RUNNING.getCode());
|
|
||||||
pipelineInstanceMapper.updateById(pipelineInstanceTb);
|
|
||||||
// 监听节点执行状态
|
|
||||||
while (true) {
|
|
||||||
ThreadUtil.safeSleep(2000);
|
|
||||||
PipelineInstanceNodeTb pipelineInstanceNode = pipelineInstanceNodeService.getPipelineInstanceNodeByArgs(instanceId, pipelineNodeTemplateVo.getCode());
|
|
||||||
if (PipelineStatusEnum.SUCCESS.getCode().equals(pipelineInstanceNode.getCurrentNodeStatus())) {
|
|
||||||
pipelineStatusEnum = PipelineStatusEnum.SUCCESS;
|
|
||||||
pipelineInstanceTb.setCurrentNodeStatus(pipelineStatusEnum.getCode());
|
|
||||||
pipelineInstanceMapper.updateById(pipelineInstanceTb);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (PipelineStatusEnum.FAIL.getCode().equals(pipelineInstanceNode.getCurrentNodeStatus())) {
|
|
||||||
pipelineStatusEnum = PipelineStatusEnum.FAIL;
|
|
||||||
pipelineInstanceTb.setCurrentNodeStatus(pipelineStatusEnum.getCode());
|
|
||||||
pipelineInstanceMapper.updateById(pipelineInstanceTb);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pipelineStatusEnum.equals(PipelineStatusEnum.FAIL)) {
|
|
||||||
// 节点失败,全失败
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ThreadUtil.safeSleep(2000);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("流水线节点运行失败", e);
|
|
||||||
pipelineInstanceTb.setStatus(PipelineStatusEnum.FAIL.getCode());
|
|
||||||
pipelineInstanceMapper.updateById(pipelineInstanceTb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pipelineInstanceTb.setStatus(pipelineStatusEnum.getCode());
|
|
||||||
pipelineInstanceMapper.updateById(pipelineInstanceTb);
|
|
||||||
pipelineInstanceDAO.unLock(pipelineInstanceTb);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("流水线运行失败", e);
|
|
||||||
pipelineInstanceTb.setStatus(PipelineStatusEnum.FAIL.getCode());
|
|
||||||
pipelineInstanceMapper.updateById(pipelineInstanceTb);
|
|
||||||
pipelineInstanceDAO.unLock(pipelineInstanceTb);
|
|
||||||
}
|
}
|
||||||
|
if (pipelineInstanceDAO.lock(pipelineInstanceTb)) {
|
||||||
|
throw new BadRequestException("流水线运行中,无法重复执行");
|
||||||
|
}
|
||||||
|
PipelineInstanceTb currentInstance = pipelineInstanceMapper.selectById(pipelineInstanceTb.getInstanceId());
|
||||||
|
if (currentInstance == null) {
|
||||||
|
throw new BadRequestException("无效流水线,请刷新页面后再试");
|
||||||
|
}
|
||||||
|
// pending、running、success、fail
|
||||||
|
List<String> canRestartStatus = new ArrayList<>() {{
|
||||||
|
add(PipelineStatusEnum.SUCCESS.getCode());
|
||||||
|
add(PipelineStatusEnum.FAIL.getCode());
|
||||||
|
}};
|
||||||
|
if (!canRestartStatus.contains(currentInstance.getStatus())) {
|
||||||
|
throw new BadRequestException("流水线运行中,无法重复执行");
|
||||||
|
}
|
||||||
|
log.info("解锁流水线, {}", JSON.toJSONString(currentInstance));
|
||||||
|
pipelineInstanceDAO.unLock(currentInstance);
|
||||||
|
pipelineJobManage.startJobByNodeCode(currentInstance, retryNodeCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void restart(PipelineInstanceTb pipelineInstanceTb) {
|
@Override
|
||||||
boolean exist = pipelineInstanceDAO.lock(pipelineInstanceTb);
|
public List<PipelineNodeDataVo> queryLastPipelineDetail(String instanceIdStr) {
|
||||||
if (exist) {
|
String realInstanceIdStr = instanceIdStr.replace(PipelineConst.INSTANCE_ID, "");
|
||||||
if (!PipelineStatusEnum.FAIL.getCode().equals(pipelineInstanceTb.getCurrentNodeStatus())) {
|
Long instanceId = Long.valueOf(realInstanceIdStr);
|
||||||
throw new BadRequestException("流水线执行中,无法重启流水线");
|
List<PipelineNodeDataVo> records = new ArrayList<>();
|
||||||
}
|
PipelineInstanceTb pipelineInstanceTb = pipelineInstanceMapper.selectById(instanceId);
|
||||||
log.info("解锁流水线, {}", JSON.toJSONString(pipelineInstanceTb));
|
if (pipelineInstanceTb == null) {
|
||||||
pipelineInstanceDAO.unLock(pipelineInstanceTb);
|
throw new BadRequestException("流水线实例不存在");
|
||||||
}
|
}
|
||||||
|
String status = pipelineInstanceTb.getStatus();
|
||||||
|
List<PipelineInstanceNodeTb> instanceNodeTbs = pipelineInstanceNodeService.queryPipelineInstanceNodeListByInstanceId(instanceId);
|
||||||
|
for (PipelineInstanceNodeTb instanceNodeTb : instanceNodeTbs) {
|
||||||
|
PipelineNodeDataVo dataVo = BeanUtil.copyProperties(instanceNodeTb, PipelineNodeDataVo.class);
|
||||||
|
dataVo.setStatus(status);
|
||||||
|
// 取流水线节点最后一步的信息
|
||||||
|
PipelineInstanceNodeDetailTb pipelineInstanceNodeDetail = pipelineInstanceNodeDetailService.getLastPipelineInstanceNodeDetailByArgs(instanceNodeTb, instanceNodeTb.getId(), instanceNodeTb.getCode());
|
||||||
|
dataVo.setCurrentNodeMsg(pipelineInstanceNodeDetail.getStepMsg());
|
||||||
|
dataVo.setCurrentNodeStatus(pipelineInstanceNodeDetail.getStepStatus());
|
||||||
|
records.add(dataVo);
|
||||||
|
}
|
||||||
|
return records;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -20,5 +20,6 @@ import java.util.List;
|
|||||||
@Mapper
|
@Mapper
|
||||||
public interface SystemOssStorageMapper extends BaseMapper<SystemOssStorageTb> {
|
public interface SystemOssStorageMapper extends BaseMapper<SystemOssStorageTb> {
|
||||||
IPage<SystemOssStorageTb> selectOssStorageByArgs(SystemQueryStorageArgs criteria, Page<SystemOssStorageTb> page);
|
IPage<SystemOssStorageTb> selectOssStorageByArgs(SystemQueryStorageArgs criteria, Page<SystemOssStorageTb> page);
|
||||||
|
|
||||||
List<SystemOssStorageTb> selectOssStorageByArgs(SystemQueryStorageArgs criteria);
|
List<SystemOssStorageTb> selectOssStorageByArgs(SystemQueryStorageArgs criteria);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-7
@@ -18,7 +18,6 @@ import cn.odboy.util.ClassUtil;
|
|||||||
import cn.odboy.util.FileUtil;
|
import cn.odboy.util.FileUtil;
|
||||||
import cn.odboy.util.StringUtil;
|
import cn.odboy.util.StringUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@@ -29,12 +28,11 @@ import java.util.*;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor(onConstructor_ = @Lazy)
|
@RequiredArgsConstructor
|
||||||
public class SystemDeptService {
|
public class SystemDeptService {
|
||||||
private final SystemDeptMapper systemDeptMapper;
|
private final SystemDeptMapper systemDeptMapper;
|
||||||
private final SystemUserMapper systemUserMapper;
|
private final SystemUserMapper systemUserMapper;
|
||||||
private final SystemRoleMapper systemRoleMapper;
|
private final SystemRoleMapper systemRoleMapper;
|
||||||
private final SystemDeptService systemDeptService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建
|
* 创建
|
||||||
@@ -45,7 +43,7 @@ public class SystemDeptService {
|
|||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void saveDept(SystemCreateDeptArgs resources) {
|
public void saveDept(SystemCreateDeptArgs resources) {
|
||||||
systemDeptMapper.insert(BeanUtil.copyProperties(resources, SystemDeptTb.class));
|
systemDeptMapper.insert(BeanUtil.copyProperties(resources, SystemDeptTb.class));
|
||||||
systemDeptService.updateDeptSubCnt(resources.getPid());
|
this.updateDeptSubCnt(resources.getPid());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,8 +63,8 @@ public class SystemDeptService {
|
|||||||
SystemDeptTb dept = systemDeptMapper.selectById(resources.getId());
|
SystemDeptTb dept = systemDeptMapper.selectById(resources.getId());
|
||||||
resources.setId(dept.getId());
|
resources.setId(dept.getId());
|
||||||
systemDeptMapper.insertOrUpdate(resources);
|
systemDeptMapper.insertOrUpdate(resources);
|
||||||
systemDeptService.updateDeptSubCnt(oldPid);
|
this.updateDeptSubCnt(oldPid);
|
||||||
systemDeptService.updateDeptSubCnt(newPid);
|
this.updateDeptSubCnt(newPid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -79,7 +77,7 @@ public class SystemDeptService {
|
|||||||
public void removeDeptByIds(Set<SystemDeptTb> deptSet) {
|
public void removeDeptByIds(Set<SystemDeptTb> deptSet) {
|
||||||
for (SystemDeptTb dept : deptSet) {
|
for (SystemDeptTb dept : deptSet) {
|
||||||
systemDeptMapper.deleteById(dept.getId());
|
systemDeptMapper.deleteById(dept.getId());
|
||||||
systemDeptService.updateDeptSubCnt(dept.getPid());
|
this.updateDeptSubCnt(dept.getPid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-7
@@ -16,7 +16,6 @@ import cn.odboy.util.ClassUtil;
|
|||||||
import cn.odboy.util.FileUtil;
|
import cn.odboy.util.FileUtil;
|
||||||
import cn.odboy.util.StringUtil;
|
import cn.odboy.util.StringUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@@ -28,12 +27,11 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor(onConstructor_ = @Lazy)
|
@RequiredArgsConstructor
|
||||||
public class SystemMenuService {
|
public class SystemMenuService {
|
||||||
private final SystemMenuMapper systemMenuMapper;
|
private final SystemMenuMapper systemMenuMapper;
|
||||||
private final SystemRoleMenuMapper systemRoleMenuMapper;
|
private final SystemRoleMenuMapper systemRoleMenuMapper;
|
||||||
private final SystemRoleService systemRoleService;
|
private final SystemRoleService systemRoleService;
|
||||||
private final SystemMenuService systemMenuService;
|
|
||||||
|
|
||||||
private static final String YES_STR = "是";
|
private static final String YES_STR = "是";
|
||||||
private static final String NO_STR = "否";
|
private static final String NO_STR = "否";
|
||||||
@@ -65,7 +63,7 @@ public class SystemMenuService {
|
|||||||
// 计算子节点数目
|
// 计算子节点数目
|
||||||
resources.setSubCount(0);
|
resources.setSubCount(0);
|
||||||
// 更新父节点菜单数目
|
// 更新父节点菜单数目
|
||||||
systemMenuService.updateMenuSubCnt(resources.getPid());
|
this.updateMenuSubCnt(resources.getPid());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,8 +120,8 @@ public class SystemMenuService {
|
|||||||
menu.setUpdateTime(null);
|
menu.setUpdateTime(null);
|
||||||
systemMenuMapper.insertOrUpdate(menu);
|
systemMenuMapper.insertOrUpdate(menu);
|
||||||
// 计算父级菜单节点数目
|
// 计算父级菜单节点数目
|
||||||
systemMenuService.updateMenuSubCnt(oldPid);
|
this.updateMenuSubCnt(oldPid);
|
||||||
systemMenuService.updateMenuSubCnt(newPid);
|
this.updateMenuSubCnt(newPid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -137,7 +135,7 @@ public class SystemMenuService {
|
|||||||
for (SystemMenuTb menu : menuSet) {
|
for (SystemMenuTb menu : menuSet) {
|
||||||
systemRoleMenuMapper.deleteRoleMenuByMenuId(menu.getId());
|
systemRoleMenuMapper.deleteRoleMenuByMenuId(menu.getId());
|
||||||
systemMenuMapper.deleteById(menu.getId());
|
systemMenuMapper.deleteById(menu.getId());
|
||||||
systemMenuService.updateMenuSubCnt(menu.getPid());
|
this.updateMenuSubCnt(menu.getPid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ services:
|
|||||||
# MinIO 社区版在 2025 年 5 月 24 日的更新中移除了 Web 管理控制台功能
|
# MinIO 社区版在 2025 年 5 月 24 日的更新中移除了 Web 管理控制台功能
|
||||||
image: minio/minio:RELEASE.2025-04-22T22-12-26Z # 原镜像`minio/minio:latest`
|
image: minio/minio:RELEASE.2025-04-22T22-12-26Z # 原镜像`minio/minio:latest`
|
||||||
restart: unless-stopped # 指定容器退出后的重启策略为始终重启,但是不考虑在Docker守护进程启动时就已经停止了的容器
|
restart: unless-stopped # 指定容器退出后的重启策略为始终重启,但是不考虑在Docker守护进程启动时就已经停止了的容器
|
||||||
volumes: # 数据卷挂载路径设置,将本机目录映射到容器目录
|
volumes: # 数据卷挂载路径设置,将本机目录映射到容器目录
|
||||||
- "./minio/data:/data"
|
- "./minio/data:/data"
|
||||||
- "./minio/minio:/minio"
|
- "./minio/minio:/minio"
|
||||||
- "./minio/config:/root/.minio"
|
- "./minio/config:/root/.minio"
|
||||||
environment: # 设置环境变量,相当于docker run命令中的-e
|
environment: # 设置环境变量,相当于docker run命令中的-e
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
LANG: en_US.UTF-8
|
LANG: en_US.UTF-8
|
||||||
#MINIO_PROMETHEUS_AUTH_TYPE: "public"
|
#MINIO_PROMETHEUS_AUTH_TYPE: "public"
|
||||||
@@ -18,7 +18,7 @@ services:
|
|||||||
driver: "json-file"
|
driver: "json-file"
|
||||||
options:
|
options:
|
||||||
max-size: "50m"
|
max-size: "50m"
|
||||||
ports: # 映射端口
|
ports: # 映射端口
|
||||||
- "9000:9000" # 文件上传&预览端口
|
- "9000:9000" # 文件上传&预览端口
|
||||||
- "9001:9001" # 控制台访问端口
|
- "9001:9001" # 控制台访问端口
|
||||||
|
|
||||||
|
|||||||
@@ -18,21 +18,21 @@ services:
|
|||||||
- ./mongodb/log:/data/log
|
- ./mongodb/log:/data/log
|
||||||
ports:
|
ports:
|
||||||
- "27017:27017"
|
- "27017:27017"
|
||||||
#networks:
|
#networks:
|
||||||
# - mongo
|
# - mongo
|
||||||
|
|
||||||
# 可视化图形工具
|
# 可视化图形工具
|
||||||
#adminmongo:
|
#adminmongo:
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/zhengqing/adminmongo # 原镜像`mrvautin/adminmongo`
|
# image: registry.cn-hangzhou.aliyuncs.com/zhengqing/adminmongo # 原镜像`mrvautin/adminmongo`
|
||||||
# restart: unless-stopped
|
# restart: unless-stopped
|
||||||
# container_name: adminmongo
|
# container_name: adminmongo
|
||||||
# environment:
|
# environment:
|
||||||
# - HOST=0.0.0.0
|
# - HOST=0.0.0.0
|
||||||
#depends_on:
|
#depends_on:
|
||||||
# - 'mongodb'
|
# - 'mongodb'
|
||||||
# links:
|
# links:
|
||||||
# - mongodb
|
# - mongodb
|
||||||
#ports:
|
#ports:
|
||||||
# - "1234:1234"
|
# - "1234:1234"
|
||||||
#networks:
|
#networks:
|
||||||
# - mongo
|
# - mongo
|
||||||
|
|||||||
@@ -5,17 +5,17 @@ services:
|
|||||||
image: registry.cn-hangzhou.aliyuncs.com/zhengqing/mysql:8.0 # 原镜像`mysql:8.0`
|
image: registry.cn-hangzhou.aliyuncs.com/zhengqing/mysql:8.0 # 原镜像`mysql:8.0`
|
||||||
container_name: mysql8 # 容器名为'mysql8'
|
container_name: mysql8 # 容器名为'mysql8'
|
||||||
restart: unless-stopped # 指定容器退出后的重启策略为始终重启,但是不考虑在Docker守护进程启动时就已经停止了的容器
|
restart: unless-stopped # 指定容器退出后的重启策略为始终重启,但是不考虑在Docker守护进程启动时就已经停止了的容器
|
||||||
volumes: # 数据卷挂载路径设置,将本机目录映射到容器目录
|
volumes: # 数据卷挂载路径设置,将本机目录映射到容器目录
|
||||||
- "./mysql/my.cnf:/etc/mysql/my.cnf"
|
- "./mysql/my.cnf:/etc/mysql/my.cnf"
|
||||||
- "./mysql/data:/var/lib/mysql"
|
- "./mysql/data:/var/lib/mysql"
|
||||||
# - "./mysql/conf.d:/etc/mysql/conf.d"
|
# - "./mysql/conf.d:/etc/mysql/conf.d"
|
||||||
- "./mysql/mysql-files:/var/lib/mysql-files"
|
- "./mysql/mysql-files:/var/lib/mysql-files"
|
||||||
environment: # 设置环境变量,相当于docker run命令中的-e
|
environment: # 设置环境变量,相当于docker run命令中的-e
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
LANG: en_US.UTF-8
|
LANG: en_US.UTF-8
|
||||||
MYSQL_ROOT_PASSWORD: lm,101208..,. # 设置root用户密码
|
MYSQL_ROOT_PASSWORD: lm,101208..,. # 设置root用户密码
|
||||||
MYSQL_DATABASE: demo # 初始化的数据库名称
|
MYSQL_DATABASE: demo # 初始化的数据库名称
|
||||||
privileged: true
|
privileged: true
|
||||||
user: root
|
user: root
|
||||||
ports: # 映射端口
|
ports: # 映射端口
|
||||||
- "23306:3306"
|
- "23306:3306"
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ services:
|
|||||||
image: registry.cn-hangzhou.aliyuncs.com/zhengqing/redis:7.0.5 # 镜像'redis:7.0.5'
|
image: registry.cn-hangzhou.aliyuncs.com/zhengqing/redis:7.0.5 # 镜像'redis:7.0.5'
|
||||||
restart: unless-stopped # 指定容器退出后的重启策略为始终重启,但是不考虑在Docker守护进程启动时就已经停止了的容器
|
restart: unless-stopped # 指定容器退出后的重启策略为始终重启,但是不考虑在Docker守护进程启动时就已经停止了的容器
|
||||||
command: redis-server /etc/redis/redis.conf # 启动redis服务并添加密码为:123456,默认不开启redis-aof方式持久化配置
|
command: redis-server /etc/redis/redis.conf # 启动redis服务并添加密码为:123456,默认不开启redis-aof方式持久化配置
|
||||||
environment: # 设置环境变量,相当于docker run命令中的-e
|
environment: # 设置环境变量,相当于docker run命令中的-e
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
LANG: en_US.UTF-8
|
LANG: en_US.UTF-8
|
||||||
volumes: # 数据卷挂载路径设置,将本机目录映射到容器目录
|
volumes: # 数据卷挂载路径设置,将本机目录映射到容器目录
|
||||||
- "./redis/data:/data"
|
- "./redis/data:/data"
|
||||||
- "./redis/config/redis.conf:/etc/redis/redis.conf" # `redis.conf`文件内容`http://download.redis.io/redis-stable/redis.conf`
|
- "./redis/config/redis.conf:/etc/redis/redis.conf" # `redis.conf`文件内容`http://download.redis.io/redis-stable/redis.conf`
|
||||||
ports: # 映射端口
|
ports: # 映射端口
|
||||||
- "26379:6379"
|
- "26379:6379"
|
||||||
|
|||||||
+1
-1
@@ -355,7 +355,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.gitee.anwena</groupId>
|
<groupId>com.gitee.anwena</groupId>
|
||||||
<artifactId>mongo-plus-boot-starter</artifactId>
|
<artifactId>mongo-plus-boot-starter</artifactId>
|
||||||
<!-- <version>2.0.9.2</version>-->
|
<!-- <version>2.0.9.2</version>-->
|
||||||
<version>2.1.6.1</version>
|
<version>2.1.6.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
Reference in New Issue
Block a user