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);
|
}
|
}
|