Files
junhong_cmp_fiber/pkg/asynctask/contract.go
break 17782d5f8e
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m20s
实现七月迭代公共技术基础
2026-07-23 17:52:48 +09:00

104 lines
3.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package asynctask 定义业务异步任务的统一公开契约。
package asynctask
import (
stderrors "errors"
"reflect"
"time"
)
const (
// StatusPending 表示任务待处理。
StatusPending = 1
// StatusProcessing 表示任务处理中。
StatusProcessing = 2
// StatusCompleted 表示任务已到达业务处理终点。
StatusCompleted = 3
// StatusFailed 表示任务整体无法执行到业务终点。
StatusFailed = 4
// StatusCancelled 表示业务明确支持且已经取消任务。
StatusCancelled = 5
)
var statusNames = map[int]string{
StatusPending: "待处理",
StatusProcessing: "处理中",
StatusCompleted: "已完成",
StatusFailed: "已失败",
StatusCancelled: "已取消",
}
// Projection 是跨业务统一的任务公开投影。
type Projection struct {
TaskID string `json:"task_id"`
Status int `json:"status"`
StatusName string `json:"status_name"`
TotalCount int `json:"total_count"`
SuccessCount int `json:"success_count"`
FailedCount int `json:"failed_count"`
Progress int `json:"progress"`
ErrorCode string `json:"error_code,omitempty"`
ErrorSummary string `json:"error_summary,omitempty"`
StartedAt *time.Time `json:"started_at,omitempty"`
CompletedAt *time.Time `json:"completed_at,omitempty"`
UpdatedAt time.Time `json:"updated_at"`
}
// TerminalResult 是构造终态投影所需的业务结果。
type TerminalResult struct {
TaskID string
Status int
TotalCount int
SuccessCount int
FailedCount int
ErrorCode string
ErrorSummary string
StartedAt *time.Time
CompletedAt *time.Time
UpdatedAt time.Time
}
// StatusName 返回固定任务状态的中文名称。
func StatusName(status int) string {
return statusNames[status]
}
// IsTerminal 判断状态是否为统一终态。
func IsTerminal(status int) bool {
return status == StatusCompleted || status == StatusFailed || status == StatusCancelled
}
// NewTerminalProjection 校验终态守恒并构造公开投影。
func NewTerminalProjection(result TerminalResult) (Projection, error) {
if !IsTerminal(result.Status) {
return Projection{}, stderrors.New("任务状态不是终态")
}
if result.TotalCount < 0 || result.SuccessCount < 0 || result.FailedCount < 0 {
return Projection{}, stderrors.New("任务结果计数不能为负数")
}
if result.Status == StatusCompleted && result.TotalCount != result.SuccessCount+result.FailedCount {
return Projection{}, stderrors.New("已完成任务的结果计数不守恒")
}
return Projection{
TaskID: result.TaskID, Status: result.Status, StatusName: StatusName(result.Status),
TotalCount: result.TotalCount, SuccessCount: result.SuccessCount, FailedCount: result.FailedCount,
Progress: 100, ErrorCode: result.ErrorCode, ErrorSummary: result.ErrorSummary,
StartedAt: result.StartedAt, CompletedAt: result.CompletedAt, UpdatedAt: result.UpdatedAt,
}, nil
}
// ValidatePayload 确保统一队列客户端接收 struct 或 map而非预序列化字节。
func ValidatePayload(payload any) error {
if payload == nil {
return stderrors.New("任务载荷不能为空")
}
kind := reflect.TypeOf(payload).Kind()
if kind != reflect.Struct && kind != reflect.Map && kind != reflect.Ptr {
return stderrors.New("任务载荷必须是结构体或 map")
}
if kind == reflect.Ptr && reflect.TypeOf(payload).Elem().Kind() != reflect.Struct {
return stderrors.New("任务载荷指针必须指向结构体")
}
return nil
}