Constraint: 在线热修前必须保存当前迭代分支全部有效代码进展 Confidence: medium Scope-risk: broad Directive: 后续修改需保持审计事件与业务事务边界一致 Tested: git diff --cached --check Not-tested: 未运行全量测试,提交用于切换分支前保存既有工作
118 lines
3.8 KiB
Go
118 lines
3.8 KiB
Go
package iot_card
|
|
|
|
import (
|
|
"context"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/break/junhong_cmp_fiber/internal/infrastructure/integrationlog"
|
|
"github.com/break/junhong_cmp_fiber/internal/model"
|
|
"github.com/break/junhong_cmp_fiber/pkg/auditcontext"
|
|
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
|
pkgerrors "github.com/break/junhong_cmp_fiber/pkg/errors"
|
|
)
|
|
|
|
type gatewayAttempt struct {
|
|
log *model.IntegrationLog
|
|
startedAt time.Time
|
|
}
|
|
|
|
func (s *Service) startGatewayCardAttempt(ctx context.Context, card *model.IotCard, operation, scene, seriesKey string, attempt int) (*gatewayAttempt, error) {
|
|
if s == nil || s.speedTierIntegration == nil {
|
|
return nil, pkgerrors.New(pkgerrors.CodeInvalidStatus, "Gateway Integration Log 接缝未配置")
|
|
}
|
|
resourceID := strconv.FormatUint(uint64(card.ID), 10)
|
|
triggerSource := auditcontext.From(ctx).Source
|
|
if triggerSource == "" {
|
|
triggerSource = "service"
|
|
}
|
|
triggerScene := scene
|
|
triggerSeries := uuid.NewSHA1(uuid.NameSpaceOID, []byte("gateway-card:"+seriesKey+":"+operation)).String()
|
|
requestID := requestIDFromContext(ctx)
|
|
var requestIDPtr *string
|
|
if requestID != "" {
|
|
requestIDPtr = &requestID
|
|
}
|
|
log, err := s.speedTierIntegration.Start(ctx, integrationlog.Attempt{
|
|
Provider: constants.IntegrationProviderGateway, Direction: constants.IntegrationDirectionOutbound,
|
|
Operation: operation, ExternalID: &card.ICCID,
|
|
ResourceType: constants.AssetTypeIotCard, ResourceID: &resourceID, ResourceKey: &card.ICCID,
|
|
TriggerSource: &triggerSource, TriggerScene: &triggerScene, TriggerSeries: &triggerSeries,
|
|
Attempt: attempt, RequestID: requestIDPtr, CorrelationID: requestIDPtr,
|
|
RequestSummary: map[string]any{"iot_card_id": card.ID, "iccid": card.ICCID},
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &gatewayAttempt{log: log, startedAt: time.Now()}, nil
|
|
}
|
|
|
|
func (s *Service) completeGatewayCardAttempt(ctx context.Context, attempt *gatewayAttempt, callErr error, stateChanged bool) error {
|
|
if attempt == nil || attempt.log == nil {
|
|
return nil
|
|
}
|
|
completion := integrationlog.Completion{
|
|
Result: constants.IntegrationResultSuccess, DurationMS: time.Since(attempt.startedAt).Milliseconds(),
|
|
StateChanged: stateChanged, ResponseSummary: map[string]any{"result": "success"},
|
|
}
|
|
if callErr != nil {
|
|
completion.Result = constants.IntegrationResultFailed
|
|
completion.SafeProviderMessage = "Gateway 请求失败"
|
|
completion.ResponseSummary = map[string]any{"result": "failed"}
|
|
if isGatewayTimeout(callErr) {
|
|
completion.Result = constants.IntegrationResultUnknown
|
|
completion.SafeProviderMessage = "Gateway 请求结果未知"
|
|
completion.ResponseSummary = map[string]any{"result": "unknown"}
|
|
completion.RecoveryStrategy = constants.GatewayQueryUnknownRecoveryStrategy
|
|
}
|
|
}
|
|
_, err := s.speedTierIntegration.Complete(ctx, attempt.log.IntegrationID, completion)
|
|
return err
|
|
}
|
|
|
|
type gatewayCardAttemptObserver struct {
|
|
service *Service
|
|
card *model.IotCard
|
|
operation string
|
|
scene string
|
|
seriesKey string
|
|
nextAttempt int
|
|
current *gatewayAttempt
|
|
successful *gatewayAttempt
|
|
lastCallErr error
|
|
recordingErr error
|
|
unknown bool
|
|
}
|
|
|
|
func (o *gatewayCardAttemptObserver) BeforeAttempt(ctx context.Context, _ int) error {
|
|
o.nextAttempt++
|
|
o.lastCallErr = nil
|
|
attempt, err := o.service.startGatewayCardAttempt(ctx, o.card, o.operation, o.scene, o.seriesKey, o.nextAttempt)
|
|
if err != nil {
|
|
o.recordingErr = err
|
|
return err
|
|
}
|
|
o.current = attempt
|
|
return nil
|
|
}
|
|
|
|
func (o *gatewayCardAttemptObserver) AfterAttempt(ctx context.Context, _ int, callErr error) error {
|
|
o.lastCallErr = callErr
|
|
if isGatewayTimeout(callErr) {
|
|
o.unknown = true
|
|
}
|
|
if callErr == nil {
|
|
o.successful = o.current
|
|
o.current = nil
|
|
return nil
|
|
}
|
|
err := o.service.completeGatewayCardAttempt(ctx, o.current, callErr, false)
|
|
o.current = nil
|
|
if err != nil {
|
|
o.recordingErr = err
|
|
}
|
|
return err
|
|
}
|