暂存一下,防止丢失
This commit is contained in:
85
internal/application/approval/dispatch_decision.go
Normal file
85
internal/application/approval/dispatch_decision.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package approval
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
)
|
||||
|
||||
// DecisionProcessingStore 管理标准决策交给业务消费者时的处理租约。
|
||||
type DecisionProcessingStore interface {
|
||||
Claim(ctx context.Context, eventID string, owner string, now time.Time, duration time.Duration) (bool, error)
|
||||
MarkSucceeded(ctx context.Context, eventID string, owner string, now time.Time) (bool, error)
|
||||
MarkFailed(ctx context.Context, eventID string, owner string, now time.Time, errorSummary string) (bool, error)
|
||||
}
|
||||
|
||||
// BusinessDecisionHandler 消费渠道无关标准决策。
|
||||
// 实现必须以审批实例 ID 和决策作为业务幂等键,并且不得依赖任何渠道 SDK、DTO 或状态码。
|
||||
type BusinessDecisionHandler interface {
|
||||
Handle(ctx context.Context, event TerminalDecisionEvent) error
|
||||
}
|
||||
|
||||
// DecisionDispatcher 使用处理租约把标准决策交给对应业务消费者。
|
||||
type DecisionDispatcher struct {
|
||||
store DecisionProcessingStore
|
||||
handlers map[string]BusinessDecisionHandler
|
||||
owner string
|
||||
logger *zap.Logger
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
// NewDecisionDispatcher 创建通用审批标准决策分发器。
|
||||
func NewDecisionDispatcher(
|
||||
store DecisionProcessingStore,
|
||||
handlers map[string]BusinessDecisionHandler,
|
||||
owner string,
|
||||
logger *zap.Logger,
|
||||
now func() time.Time,
|
||||
) *DecisionDispatcher {
|
||||
if logger == nil {
|
||||
logger = zap.NewNop()
|
||||
}
|
||||
if now == nil {
|
||||
now = time.Now
|
||||
}
|
||||
return &DecisionDispatcher{store: store, handlers: handlers, owner: owner, logger: logger, now: now}
|
||||
}
|
||||
|
||||
// Consume 幂等消费一条标准决策;重复投递或其他有效租约正在处理时正常结束。
|
||||
func (d *DecisionDispatcher) Consume(ctx context.Context, event TerminalDecisionEvent) error {
|
||||
if d == nil || d.store == nil || d.owner == "" || event.EventID == "" || event.InstanceID == 0 || event.BusinessType == "" {
|
||||
return errors.New(errors.CodeInternalError, "通用审批决策分发器未完整配置")
|
||||
}
|
||||
handler := d.handlers[event.BusinessType]
|
||||
if handler == nil {
|
||||
return errors.New(errors.CodeServiceUnavailable, "审批业务消费者尚未注册")
|
||||
}
|
||||
now := d.now().UTC()
|
||||
claimed, err := d.store.Claim(ctx, event.EventID, d.owner, now, constants.ApprovalDecisionDeliveryLeaseDuration)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !claimed {
|
||||
return nil
|
||||
}
|
||||
if err := handler.Handle(ctx, event); err != nil {
|
||||
if _, markErr := d.store.MarkFailed(ctx, event.EventID, d.owner, d.now().UTC(), "业务消费者处理失败"); markErr != nil {
|
||||
d.logger.Error("审批标准决策失败状态保存失败",
|
||||
zap.String("event_id", event.EventID), zap.Uint("approval_instance_id", event.InstanceID),
|
||||
zap.String("business_type", event.BusinessType), zap.Error(markErr))
|
||||
}
|
||||
return err
|
||||
}
|
||||
marked, err := d.store.MarkSucceeded(ctx, event.EventID, d.owner, d.now().UTC())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !marked {
|
||||
return errors.New(errors.CodeConflict, "审批标准决策处理租约已失效")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user