刘光辉
3 小时以前 06f314545ac3514d7ce28939920866ae8188d31c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package jnpf.dmsService.pdf;
 
import jnpf.base.ActionResult;
import jnpf.dms.DmsPersistentPdfApi;
import jnpf.dmsEntity.permission.entity.DmsFileVersionEntity;
import jnpf.dmsEntity.storage.entity.DmsFileObjectEntity;
import jnpf.dmsEntity.storage.form.DmsPersistentPdfGenerateForm;
import jnpf.dmsEntity.storage.pdf.DmsPdfGenerationTask;
import jnpf.dmsEntity.storage.vo.DmsPersistentPdfGenerateVO;
import jnpf.dmsMapper.DmsFileObjectMapper;
import jnpf.dmsMapper.DmsFileVersionMapper;
import jnpf.dmsMapper.DmsPdfGenerationTaskMapper;
import jnpf.exception.DataException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
 
import java.util.UUID;
 
@Slf4j
@Service
@EnableScheduling
@RequiredArgsConstructor
@ConditionalOnProperty(name = "dms.pdf-generation.worker-enabled", havingValue = "true")
public class DmsPdfGenerationJob {
    private final DmsPdfGenerationTaskMapper tasks;
    private final DmsFileVersionMapper versions;
    private final DmsFileObjectMapper objects;
    private final DmsPersistentPdfApi fileApi;
    private final DmsPdfGenerationCompletion completion;
 
    @Value("${dms.pdf-generation.batch-size:20}") private int batchSize;
    @Value("${dms.pdf-generation.max-attempts:8}") private int maxAttempts;
    @Value("${dms.pdf-generation.lease-seconds:300}") private int leaseSeconds;
    @Value("${dms.pdf-generation.backfill-enabled:false}") private boolean backfillEnabled;
 
    @Scheduled(cron = "${dms.pdf-generation.cron:*/30 * * * * ?}")
    public void generateDue() {
        if (backfillEnabled) tasks.discover(Math.max(1, batchSize));
        for (DmsPdfGenerationTask task : tasks.candidates(Math.max(1, batchSize), maxAttempts)) {
            process(task);
        }
    }
 
    void process(DmsPdfGenerationTask task) {
        String token = UUID.randomUUID().toString();
        if (tasks.claim(task.getTenantId(), task.getFileVersionId(), token,
                maxAttempts, leaseSeconds) != 1) return;
        try {
            DmsFileVersionEntity version = versions.selectByTenantAndId(
                    task.getTenantId(), task.getFileVersionId());
            DmsFileObjectEntity object = objects.selectByTenantAndFileVersionId(
                    task.getTenantId(), task.getFileVersionId());
            if (version == null || object == null
                    || !task.getSourceChecksumSha256().equalsIgnoreCase(version.getChecksumSha256())) {
                throw new DataException("持久化 PDF 源文件不存在或已变化");
            }
            ActionResult<DmsPersistentPdfGenerateVO> response = fileApi.generate(
                    "jnpf-dms", form(task, version, object));
            if (response == null || !Integer.valueOf(200).equals(response.getCode())
                    || response.getData() == null) {
                throw new DataException(response == null || response.getMsg() == null
                        ? "文件服务未返回持久化 PDF" : response.getMsg());
            }
            completion.succeed(task, token, response.getData());
        } catch (RuntimeException error) {
            int attempts = task.getAttempts() == null ? 1 : task.getAttempts() + 1;
            boolean terminal = attempts >= maxAttempts;
            tasks.fail(task.getTenantId(), task.getFileVersionId(), token,
                    message(error), retryDelay(attempts), terminal);
            log.warn("DMS 持久化 PDF 生成失败 tenant={} version={} attempts={}",
                    task.getTenantId(), task.getFileVersionId(), attempts, error);
        }
    }
 
    private DmsPersistentPdfGenerateForm form(DmsPdfGenerationTask task,
                                               DmsFileVersionEntity version,
                                               DmsFileObjectEntity object) {
        DmsPersistentPdfGenerateForm form = new DmsPersistentPdfGenerateForm();
        form.setTenantId(task.getTenantId());
        form.setFileVersionId(task.getFileVersionId());
        form.setFileName(version.getFileName());
        form.setMimeType(version.getMimeType());
        form.setSizeBytes(version.getSizeBytes());
        form.setStoragePlatform(object.getStoragePlatform());
        form.setBucketName(object.getBucketName());
        form.setBasePath(object.getBasePath());
        form.setObjectPath(object.getObjectPath());
        form.setObjectName(object.getObjectName());
        form.setSourceChecksumSha256(task.getSourceChecksumSha256());
        return form;
    }
 
    static int retryDelay(int attempts) {
        int[] delays = {60, 300, 900, 3600, 21600};
        return delays[Math.min(Math.max(attempts - 1, 0), delays.length - 1)];
    }
 
    private String message(Throwable error) {
        String value = error.getMessage();
        if (value == null || value.isBlank()) value = error.getClass().getSimpleName();
        return value.length() <= 1000 ? value : value.substring(0, 1000);
    }
}