Files
junhong_cmp_fiber/internal/infrastructure/wecom/approval_submission_consumer.go
break 73f5125d3d
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m26s
七月迭代短暂完结,还有很多后端的关键东西没有弄,这是一版赶时间做的东西
2026-07-25 17:06:58 +08:00

101 lines
3.8 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 wecom
import (
"context"
stdErrors "errors"
"github.com/bytedance/sonic"
"github.com/hibiken/asynq"
approvalapp "github.com/break/junhong_cmp_fiber/internal/application/approval"
"github.com/break/junhong_cmp_fiber/internal/infrastructure/messaging/outbox"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/errors"
)
// ApprovalSubmissionConsumer 消费通用审批提交 Outbox并保证结果未知时不盲目重提。
type ApprovalSubmissionConsumer struct {
repository *ApprovalContextRepository
client *ApprovalSubmissionClient
attachments approvalAttachmentPort
}
// NewApprovalSubmissionConsumer 创建企业微信审批提交消费者。
func NewApprovalSubmissionConsumer(repository *ApprovalContextRepository, client *ApprovalSubmissionClient, attachments approvalAttachmentPort) *ApprovalSubmissionConsumer {
return &ApprovalSubmissionConsumer{repository: repository, client: client, attachments: attachments}
}
// Consume 校验通用事件并提交一次企业微信审批申请。
func (c *ApprovalSubmissionConsumer) Consume(ctx context.Context, envelope outbox.DeliveryEnvelope) error {
if c == nil || c.repository == nil || c.client == nil {
return errors.New(errors.CodeServiceUnavailable, "企业微信审批提交消费者未配置")
}
if envelope.PayloadVersion != constants.ApprovalSubmissionPayloadVersionV1 {
return stdErrors.Join(asynq.SkipRetry, errors.New(errors.CodeInvalidParam, "不支持的审批提交事件版本"))
}
var event approvalapp.SubmissionRequestedEvent
if err := sonic.Unmarshal(envelope.Payload, &event); err != nil {
return stdErrors.Join(asynq.SkipRetry, errors.New(errors.CodeInvalidParam, "审批提交事件载荷无效"))
}
if event.InstanceID == 0 || event.Provider != constants.IntegrationProviderWeCom {
return stdErrors.Join(asynq.SkipRetry, errors.New(errors.CodeInvalidParam, "审批提交事件渠道或实例无效"))
}
record, claimed, err := c.repository.ClaimSubmission(ctx, event.InstanceID)
if err != nil {
return err
}
if !claimed {
return nil
}
form, err := buildApprovalForm(
ctx, record.Context.ApplicationID, event.InstanceID,
record.Context.ControlMapping, record.Context.TemplateSnapshot, record.Instance.RequestSnapshot, c.attachments,
)
if err != nil {
var attachmentErr *attachmentPreparationError
if stdErrors.As(err, &attachmentErr) {
if releaseErr := c.repository.ReleaseForRetry(ctx, event.InstanceID, "审批附件准备失败,等待重试"); releaseErr != nil {
return releaseErr
}
return err
}
if markErr := c.repository.MarkFailed(ctx, event.InstanceID, err.Error()); markErr != nil {
return markErr
}
return nil
}
result, submitErr := c.client.Submit(ctx, ApprovalSubmitRequest{
InstanceID: event.InstanceID, ApplicationID: record.Context.ApplicationID,
TemplateID: record.Context.TemplateID, CreatorUserID: record.Context.CreatorUserID,
CorrelationID: event.CorrelationID, Contents: form.Contents,
})
switch result.Outcome {
case submissionOutcomeSuccess:
if err := c.repository.MarkSubmitted(ctx, event.InstanceID, result.SPNo); err != nil {
return err
}
case submissionOutcomeUnknown:
if err := c.repository.MarkUnknown(ctx, event.InstanceID, result.Message); err != nil {
return err
}
case submissionOutcomeFailed:
if result.SafeToRetry {
if err := c.repository.ReleaseForRetry(ctx, event.InstanceID, result.Message); err != nil {
return err
}
if submitErr != nil {
return submitErr
}
return errors.New(errors.CodeServiceUnavailable, result.Message)
}
if err := c.repository.MarkFailed(ctx, event.InstanceID, result.Message); err != nil {
return err
}
default:
return errors.New(errors.CodeInternalError, "企业微信审批提交结果无效")
}
return submitErr
}
var _ outbox.EventConsumer = (*ApprovalSubmissionConsumer)(nil)