Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Turbo运营数据统计 #156 #162

Merged
merged 25 commits into from
Dec 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b4549f5
feat:编译加速运营数据统计 #156
eazence Dec 18, 2023
235f83c
feat:编译加速运营数据统计 #156
eazence Dec 20, 2023
0cd76bd
feat:编译加速运营数据统计 #156
eazence Dec 20, 2023
8db325d
feat:编译加速运营数据统计 #156
eazence Dec 20, 2023
494000d
feat:编译加速运营数据统计 #156
eazence Dec 21, 2023
88ebcdb
feat:编译加速运营数据统计 #156
eazence Dec 21, 2023
e201871
feat:编译加速运营数据统计 #156
eazence Dec 21, 2023
09f7b68
feat:编译加速运营数据统计 #156
eazence Dec 21, 2023
c04c175
feat:编译加速运营数据统计 #156
eazence Dec 21, 2023
b818f17
feat:编译加速运营数据统计 #156
eazence Dec 25, 2023
f3b77bb
feat:编译加速运营数据统计 #156
eazence Dec 25, 2023
89c6843
feat:编译加速运营数据统计 #156
eazence Dec 25, 2023
df1d819
feat:编译加速运营数据统计 #156
eazence Dec 25, 2023
5b7f22d
feat:编译加速运营数据统计 #156
eazence Dec 25, 2023
f810f9f
feat:编译加速运营数据统计 #156
eazence Dec 25, 2023
26af802
feat:编译加速运营数据统计 #156
eazence Dec 25, 2023
af1cf05
feat:编译加速运营数据统计 #156
eazence Dec 25, 2023
d147324
feat:编译加速运营数据统计 #156
eazence Dec 25, 2023
691240e
feat:编译加速运营数据统计 #156
eazence Dec 25, 2023
3e677a4
feat:编译加速运营数据统计 #156
eazence Dec 25, 2023
3f4c1a5
feat:编译加速运营数据统计 #156
eazence Dec 25, 2023
d0592c1
feat:编译加速运营数据统计 #156
eazence Dec 25, 2023
6ecbaee
feat:编译加速运营数据统计 #156
eazence Dec 26, 2023
0a9f387
feat:编译加速运营数据统计 #156
eazence Dec 26, 2023
5c5612b
Merge branch 'master' into issue_156
eazence Dec 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package com.tencent.devops.turbo.api
import com.tencent.devops.common.util.constants.AUTH_HEADER_DEVOPS_PROJECT_ID
import com.tencent.devops.common.util.constants.AUTH_HEADER_DEVOPS_USER_ID
import com.tencent.devops.turbo.pojo.CustomScheduleJobModel
import com.tencent.devops.api.pojo.Response
import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import io.swagger.annotations.ApiParam
import org.springframework.http.MediaType
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
Expand Down Expand Up @@ -34,7 +36,24 @@ interface IUserCustomScheduleTaskController {
@ApiParam(value = "编译加速模式信息", required = true)
@RequestBody
customScheduleJobModel: CustomScheduleJobModel
): Boolean
): Response<Boolean>

@ApiOperation("删除计划任务")
@DeleteMapping(
"/deleteScheduleJob",
produces = [MediaType.APPLICATION_JSON_VALUE]
)
fun deleteScheduleJob(
@ApiParam(value = "用户信息", required = true)
@RequestHeader(AUTH_HEADER_DEVOPS_USER_ID)
user: String,
@ApiParam(value = "项目id", required = true)
@RequestHeader(AUTH_HEADER_DEVOPS_PROJECT_ID)
projectId: String,
@ApiParam(value = "任务名称", required = true)
@RequestParam(value = "jobName")
jobName: String
): Response<Boolean>

@ApiOperation("触发定时任务执行")
@GetMapping(
Expand All @@ -51,5 +70,5 @@ interface IUserCustomScheduleTaskController {
@ApiParam(value = "任务名称", required = true)
@RequestParam(value = "jobName")
jobName: String
): String?
): Response<String>
}
4 changes: 2 additions & 2 deletions src/backend/turbo/biz-turbo/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ dependencies {
api("com.tencent.bk.devops.ci.common:common-api:${Versions.ciVersion}"){
isTransitive = false
}
api("com.tencent.bk.devops.ci.auth:api-auth:${Versions.ciAuthVersion}"){
api("com.tencent.bk.devops.ci.auth:api-auth:${Versions.ciVersion}"){
isTransitive = false
}
api("com.tencent.bk.devops.ci.common:common-auth-api:${Versions.ciAuthVersion}"){
api("com.tencent.bk.devops.ci.common:common-auth-api:${Versions.ciVersion}"){
isTransitive = false
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.tencent.devops.turbo.controller

import com.tencent.devops.api.pojo.Response
import com.tencent.devops.common.api.exception.TurboException
import com.tencent.devops.common.api.exception.code.IS_NOT_ADMIN_MEMBER
import com.tencent.devops.common.util.constants.NO_ADMIN_MEMBER_MESSAGE
Expand All @@ -21,17 +22,24 @@ class UserCustomScheduleTaskController @Autowired constructor(
user: String,
projectId: String,
customScheduleJobModel: CustomScheduleJobModel
): Boolean {
if (!turboAuthService.validatePlatformMember(projectId, user)) {
): Response<Boolean> {
if (!turboAuthService.getAuthResult(projectId, user)) {
throw TurboException(errorCode = IS_NOT_ADMIN_MEMBER, errorMessage = NO_ADMIN_MEMBER_MESSAGE)
}
return Response.success(customScheduleJobService.customScheduledJobAdd(customScheduleJobModel))
}

override fun deleteScheduleJob(user: String, projectId: String, jobName: String): Response<Boolean> {
if (!turboAuthService.getAuthResult(projectId, user)) {
throw TurboException(errorCode = IS_NOT_ADMIN_MEMBER, errorMessage = NO_ADMIN_MEMBER_MESSAGE)
}
return customScheduleJobService.customScheduledJobAdd(customScheduleJobModel)
return Response.success(customScheduleJobService.customScheduledJobDel(jobName))
}

override fun triggerCustomScheduleJob(user: String, projectId: String, jobName: String): String? {
override fun triggerCustomScheduleJob(user: String, projectId: String, jobName: String): Response<String> {
if (!turboAuthService.getAuthResult(projectId, user)) {
throw TurboException(errorCode = IS_NOT_ADMIN_MEMBER, errorMessage = NO_ADMIN_MEMBER_MESSAGE)
}
return customScheduleJobService.trigger(jobName)
return Response.success(customScheduleJobService.trigger(jobName))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.tencent.devops.turbo.dao.repository

import com.tencent.devops.turbo.model.TTbsDaySummaryEntity
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.stereotype.Repository

@Repository
interface TbsDaySummaryRepository : MongoRepository<TTbsDaySummaryEntity, String> {
/**
* 根据日期删除
*/
fun removeAllByDay(day: String)
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,9 @@ interface TurboPlanRepository : MongoRepository<TTurboPlanEntity, String> {
* 根据项目id和编译加速方案名称和id判断是否存在
*/
fun existsByProjectIdAndPlanNameAndIdNot(projectId: String, planName: String, planId: String): Boolean

/**
* 根据方案id集合批量查询
*/
fun findByIdIn(planIdSet: List<String?>): List<TTurboPlanEntity>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.tencent.devops.turbo.dto

import com.fasterxml.jackson.annotation.JsonProperty

data class TBSDaySummaryDto(
val day: String,

val user: String?,

@JsonProperty("project_id")
val projectId: String,

/**
* 加速时长(单位:秒)
*/
@JsonProperty("total_time")
val totalTime: Double,

/**
* 加速时长*cpu核数(单位秒*核)
*/
@JsonProperty("total_time_with_cpu")
val totalTimeWithCpu: Double,

/**
* 加速次数
*/
@JsonProperty("total_record_number")
val totalRecordNumber: Double,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package com.tencent.devops.turbo.job

import com.tencent.devops.common.client.Client
import com.tencent.devops.common.util.DateTimeUtils
import com.tencent.devops.common.util.JsonUtil
import com.tencent.devops.project.api.service.ServiceProjectResource
import com.tencent.devops.project.pojo.ProjectVO
import com.tencent.devops.turbo.dao.repository.TbsDaySummaryRepository
import com.tencent.devops.turbo.dao.repository.TurboEngineConfigRepository
import com.tencent.devops.turbo.dao.repository.TurboPlanRepository
import com.tencent.devops.turbo.dto.TBSDaySummaryDto
import com.tencent.devops.turbo.model.TTbsDaySummaryEntity
import com.tencent.devops.turbo.sdk.TBSSdkApi
import org.quartz.Job
import org.quartz.JobExecutionContext
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import java.time.LocalDate
import java.time.LocalDateTime

@Suppress("SpringJavaAutowiredMembersInspection")
class TBSDaySummaryJob @Autowired constructor(
private val client: Client,
private val tbsDaySummaryRepository: TbsDaySummaryRepository,
private val turboEngineConfigRepository: TurboEngineConfigRepository,
private val turboPlanRepository: TurboPlanRepository
) : Job {

companion object {
private val logger = LoggerFactory.getLogger(this::class.java)
private const val PAGE_SIZE = 3000
}

/**
* 执行入口
*/
override fun execute(context: JobExecutionContext) {
logger.info("TBS day summary job start executing: ${JsonUtil.toJson(context.jobDetail)}")

val jobParam = context.jobDetail.jobDataMap
val statisticsDateStr = if (jobParam.containsKey("statisticsDate")) {
jobParam["statisticsDate"] as String
} else {
// 统计昨天
val statLocalDate = LocalDate.now().minusDays(1)
DateTimeUtils.localDate2DateStr(statLocalDate)
}

// 清理待统计的数据,防止重复统计
tbsDaySummaryRepository.removeAllByDay(statisticsDateStr)

val projectVOMap = mutableMapOf<String, ProjectVO>()

val engineConfigEntities = turboEngineConfigRepository.findAll()
engineConfigEntities.forEach { engineConfig ->
logger.info("query engineConfig: ${engineConfig.engineCode}")
val daySummaryDtoList = try {
TBSSdkApi.queryTbsDaySummary(
engineCode = engineConfig.engineCode,
queryParam = mapOf(
"day" to statisticsDateStr
)
)
} catch (e: Exception) {
logger.error("queryTbsDaySummary error: ${e.message}")
return@forEach
}

logger.info("daySummaryDtoList size: ${daySummaryDtoList.size}")
if (daySummaryDtoList.isEmpty()) {
logger.warn("queryTbsDaySummary result is empty! engineCode: ${engineConfig.engineCode}")
return@forEach
}

// 把TBS的接口数据整理成entity
val summaryEntityList = this.dto2SummaryEntityList(daySummaryList = daySummaryDtoList)
val summaryListList = summaryEntityList.chunked(PAGE_SIZE)
for (summaryList in summaryListList) {

// 根据planId批量获取方案信息
val planIds = summaryList.map { it.planId }.toSet()
val turboPlanList = turboPlanRepository.findByIdIn(planIds.toList())
logger.info("turboPlanRepository.findByIdIn result size: ${turboPlanList.size}")
val planEntityMap = turboPlanList.associateBy { it.id }

// 赋值plan信息和项目id
for (summaryEntity in summaryList) {
val planEntity = planEntityMap[summaryEntity.planId]
summaryEntity.planCreator = planEntity?.createdBy
summaryEntity.planName = planEntity?.planName
summaryEntity.projectId = planEntity?.projectId
}

// 取出项目ID集合用于获取项目组织架构信息
val projectIdSet = turboPlanList.map { it.projectId }.toSet()
val notInProjectMapKeySet = projectIdSet.subtract(projectVOMap.keys)

// 获取项目信息清单
val projectVOList = this.getProjectVOListByProjectIds(projectIds = notInProjectMapKeySet.toList())
if (projectVOList.isNotEmpty()) {
projectVOMap.putAll(projectVOList.associateBy { it.englishName })
}

for (it in summaryList) {
it.projectName = projectVOMap[it.projectId]?.projectName
it.bgName = projectVOMap[it.projectId]?.bgName
it.bgId = projectVOMap[it.projectId]?.bgId?.toInt()
it.deptName = projectVOMap[it.projectId]?.deptName
it.deptId = projectVOMap[it.projectId]?.deptId?.toInt()
it.centerName = projectVOMap[it.projectId]?.centerName
it.centerId = projectVOMap[it.projectId]?.centerId?.toInt()
it.productId = projectVOMap[it.projectId]?.productId
}
}

tbsDaySummaryRepository.saveAll(summaryEntityList)
logger.info("save summary entity size: ${summaryEntityList.size}")
}
logger.info("TBS day summary job execution completed!")
}

/**
* 把TBS的接口数据整理成entity
*/
private fun dto2SummaryEntityList(daySummaryList: List<TBSDaySummaryDto>): List<TTbsDaySummaryEntity> {
val summaryEntities = mutableListOf<TTbsDaySummaryEntity>()

daySummaryList.forEach { summary ->
// distcc与其它不一样,它的projectId就是planId
val planIdAndEngineCode = summary.projectId

val planId: String
val engineCode: String

// "60d54b87a26123319d011bob_cc"
if (planIdAndEngineCode.contains("_")) {
val stringArr = planIdAndEngineCode.split("_")
planId = stringArr[0]
engineCode = if (stringArr[1] == "cc") "disttask-cc" else if (stringArr[1] == "ue4") "disttask-ue4"
else stringArr[1]
} else {
planId = planIdAndEngineCode
engineCode = "distcc"
}

val entity = TTbsDaySummaryEntity(
day = summary.day,
engineCode = engineCode,
planId = planId,
user = if (engineCode == "disttask-ue4") summary.user else null,
totalTime = summary.totalTime,
totalTimeWithCpu = summary.totalTimeWithCpu,
totalRecordNumber = summary.totalRecordNumber,
createdDate = LocalDateTime.now()
)
summaryEntities.add(entity)
}
return summaryEntities
}

/**
* 根据项目id获取项目信息
*/
private fun getProjectVOListByProjectIds(projectIds: List<String>): List<ProjectVO> {
var list = emptyList<ProjectVO>()
if (projectIds.isNotEmpty()) {
val result = client.get(ServiceProjectResource::class.java).listByProjectCodeList(projectIds)
if (result.isNotOk() || result.data == null) {
logger.error("ServiceProjectResource#get request is failed!")
return list
}
list = result.data!!
}
return list
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.tencent.devops.turbo.config.TBSProperties
import com.tencent.devops.turbo.dto.DistccRequestBody
import com.tencent.devops.turbo.dto.DistccResponse
import com.tencent.devops.turbo.dto.ParamEnumDto
import com.tencent.devops.turbo.dto.TBSDaySummaryDto
import com.tencent.devops.turbo.dto.TBSTurboStatDto
import com.tencent.devops.turbo.dto.WhiteListDto
import com.tencent.devops.web.util.SpringContextHolder
Expand Down Expand Up @@ -122,13 +123,17 @@ object TBSSdkApi {
queryParam: Map<String, Any> = mutableMapOf(),
jsonBody: String = "",
headers: MutableMap<String, String> = mutableMapOf(),
method: String = "GET"
method: String = "GET",
customPath: String? = null
): String {
val requestBody = jsonBody.toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
val properties = SpringContextHolder.getBean<TBSProperties>()
val customPath =
val templatePath =
properties.urlTemplate!!.replace("{engine}", engineCode).replace("{resource_type}", resourceName)
var url = "${properties.rootPath}/$customPath"
var url = "${properties.rootPath}/$templatePath"
if (!customPath.isNullOrBlank()) {
url = url.plus(customPath)
}
if (pathParam.isNotEmpty()) {
pathParam.forEach {
url = url.plus("/$it")
Expand Down Expand Up @@ -207,4 +212,32 @@ object TBSSdkApi {
JsonUtil.to(responseStr, object : TypeReference<DistccResponse<MutableList<String>>>() {}).data
}
}

/**
* 获取TBS每日汇总统计
*/
fun queryTbsDaySummary(engineCode: String, queryParam: Map<String, Any>): List<TBSDaySummaryDto> {
val responseStr = if (engineCode.contains("disttask")) {
// tbs后台接口路径处理
tbsCommonRequest(
engineCode = "disttask",
resourceName = "summary",
queryParam = queryParam,
customPath = if (engineCode.contains("ue4"))"/groupbyuser/scene/ue4" else null
)
} else {
tbsCommonRequest(
engineCode = engineCode,
resourceName = "summary",
queryParam = queryParam
)
}
val response = JsonUtil.to(responseStr, object : TypeReference<DistccResponse<List<TBSDaySummaryDto>>>() {})
if (response.code != 0 || !response.result) {
throw TurboException(errorCode = TURBO_THIRDPARTY_SYSTEM_FAIL, errorMessage = "fail to invoke request: "
+ response.message
)
}
return response.data ?: listOf()
}
}
Loading
Loading