package orbit import ( "bytes" "context" "encoding/json" "errors" "io" "strconv" "strings" ) type handlerCompletion struct { attemptID string result WorkerFinish } func (w *Worker) invoke(ctx context.Context, handler WorkerHandler, execution WorkerExecution, ref WorkerAttempt, results chan<- handlerCompletion, runDone <-chan struct{}) { out := WorkerFinish{Ref: ref, Outcome: WorkerUnknown, ErrorCode: "HANDLER_ABORTED", Result: json.RawMessage(`{}`)} completed := false defer func() { if recover() != nil { out = unknownHandlerResult(ref, "HANDLER_PANIC") } else if !completed { out = unknownHandlerResult(ref, "HANDLER_ABORTED") } w.running.Add(-1) select { case results <- handlerCompletion{attemptID: ref.AttemptID, result: out}: case <-runDone: } }() if ctx.Err() != nil { out = unknownHandlerResult(ref, "LEASE_LOST") if errors.Is(context.Cause(ctx), ErrTaskCancellationRequested) { out = cancelledHandlerResult(ref, nil) } completed = true return } w.started.Add(1) result, err := handler.Handle(ctx, execution) if err == nil { result = append(json.RawMessage(nil), result...) if validHandlerResult(result) { out = WorkerFinish{Ref: ref, Outcome: WorkerSucceeded, Result: result} } else { out = unknownHandlerResult(ref, "INVALID_HANDLER_RESULT") } } else { var known *WorkerFailure var cancelled *WorkerCancellationConfirmed if errors.As(err, &cancelled) && cancelled != nil && errors.Is(context.Cause(ctx), ErrTaskCancellationRequested) { out = cancelledHandlerResult(ref, cancelled.Details) } else if errors.As(err, &known) && known != nil && workerName(known.Code, 64) { details := append(json.RawMessage(nil), known.Details...) if len(details) == 0 { details = json.RawMessage(`{}`) } if validHandlerResult(details) { out = WorkerFinish{Ref: ref, Outcome: WorkerFailed, ErrorCode: known.Code, Result: details, Retryable: known.Retryable} } else { out = unknownHandlerResult(ref, "INVALID_HANDLER_RESULT") } } else if errors.Is(context.Cause(ctx), ErrExecutionLeaseLost) { out = unknownHandlerResult(ref, "LEASE_LOST") } else { out = unknownHandlerResult(ref, "HANDLER_ERROR") } } completed = true } func cancelledHandlerResult(ref WorkerAttempt, details json.RawMessage) WorkerFinish { details = append(json.RawMessage(nil), details...) if len(details) == 0 { details = json.RawMessage(`{}`) } if !validHandlerResult(details) { return unknownHandlerResult(ref, "INVALID_HANDLER_RESULT") } return WorkerFinish{Ref: ref, Outcome: WorkerCancelled, ErrorCode: "CANCEL_CONFIRMED", Result: details} } func unknownHandlerResult(ref WorkerAttempt, code string) WorkerFinish { return WorkerFinish{Ref: ref, Outcome: WorkerUnknown, ErrorCode: code, Result: json.RawMessage(`{}`)} } // validHandlerResult 提前拒绝服务端无法持久化的结果,避免失效报告无限重报。 // 只检验数值范围;不把精确业务数字改写成 float64。 func validHandlerResult(raw json.RawMessage) bool { if len(raw) == 0 || len(raw) > 256<<10 || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return false } // 预留 task.finish 的信封/body 嵌套,避免合法结果单独校验后在帧校验阶段超深。 frame := append([]byte(`{"body":{"result":`), raw...) frame = append(frame, []byte(`}}`)...) if validateWorkerJSON(frame) != nil { return false } d := json.NewDecoder(bytes.NewReader(raw)) d.UseNumber() for { value, err := d.Token() if err == io.EOF { return true } if err != nil { return false } number, ok := value.(json.Number) if !ok { continue } s := string(number) if len(s) > 256 { return false } if _, err := strconv.ParseFloat(s, 64); err != nil { return false } s = strings.TrimPrefix(s, "-") exponent := 0 if i := strings.IndexAny(s, "eE"); i >= 0 { var err error exponent, err = strconv.Atoi(s[i+1:]) if err != nil || exponent < -308 || exponent > 308 { return false } s = s[:i] } if i := strings.IndexByte(s, '.'); i >= 0 { exponent -= len(s) - i - 1 s = s[:i] + s[i+1:] } s = strings.TrimLeft(s, "0") if s == "" { continue } for strings.HasSuffix(s, "0") { s = s[:len(s)-1] exponent++ } if exponent < -308 || exponent > 308 || exponent+len(s)-1 > 308 { return false } } }