You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot @Scheduled任务实现S3文件上传按需暂停/恢复方案咨询

基于Spring Boot后端实现S3上传任务的暂停/恢复/追踪方案

核心思路:改造@Scheduled调度器为可控制任务

@Scheduled默认由Spring任务调度器管理独立线程,但通过外部状态控制+任务拆分,无需完全重写现有上传逻辑就能实现暂停/恢复功能。

1. 新增任务状态管理Bean

创建全局状态管理类,存储任务状态与上传进度,保证线程安全:

@Component
public class S3UploadTaskStatus {
    private volatile boolean paused = false;
    private AtomicLong uploadedBytes = new AtomicLong(0);
    private AtomicLong totalBytes = new AtomicLong(0);

    public void pause() {
        this.paused = true;
    }

    public void resume() {
        this.paused = false;
    }

    public void updateUploadedBytes(long bytes) {
        uploadedBytes.addAndGet(bytes);
    }

    public void setTotalBytes(long bytes) {
        totalBytes.set(bytes);
    }

    public boolean isPaused() {
        return paused;
    }

    public double getProgress() {
        return totalBytes.get() == 0 ? 0 : (double) uploadedBytes.get() / totalBytes.get();
    }
}

2. 改造原有@Scheduled任务

在上传逻辑中加入状态检查,拆分任务单元(单文件/分片),实现即时暂停与进度追踪:

@Component
public class S3UploadScheduler {
    @Autowired
    private AmazonS3 amazonS3;
    @Autowired
    private S3UploadTaskStatus taskStatus;

    @Scheduled(fixedRate = 5000) // 保留原调度频率
    public void uploadToS3() {
        if (taskStatus.isPaused()) {
            return;
        }

        List<File> filesToUpload = getFilesToUpload();
        taskStatus.setTotalBytes(calculateTotalBytes(filesToUpload));
        
        for (File file : filesToUpload) {
            if (taskStatus.isPaused()) {
                break;
            }
            
            // 大文件可替换为AWS分片上传逻辑
            PutObjectRequest request = new PutObjectRequest("your-bucket", file.getName(), file);
            request.setGeneralProgressListener(progressEvent -> {
                taskStatus.updateUploadedBytes(progressEvent.getBytesTransferred());
            });
            
            amazonS3.putObject(request);
        }
    }
}

3. 暴露后端API供UI调用

创建Controller提供暂停/恢复/进度查询接口:

@RestController
@RequestMapping("/upload/task")
public class UploadTaskController {
    @Autowired
    private S3UploadTaskStatus taskStatus;

    @PostMapping("/pause")
    public ResponseEntity<Void> pauseTask() {
        taskStatus.pause();
        return ResponseEntity.ok().build();
    }

    @PostMapping("/resume")
    public ResponseEntity<Void> resumeTask() {
        taskStatus.resume();
        return ResponseEntity.ok().build();
    }

    @GetMapping("/progress")
    public ResponseEntity<Map<String, Object>> getProgress() {
        Map<String, Object> progress = new HashMap<>();
        progress.put("status", taskStatus.isPaused() ? "PAUSED" : "RUNNING");
        progress.put("progress", taskStatus.getProgress());
        return ResponseEntity.ok(progress);
    }
}

4. UI端简单实现

通过定时请求进度接口展示状态,提供操作按钮:

<div>
    <h3>S3上传任务状态</h3>
    <div>当前进度:<span id="progress">0%</span></div>
    <div>当前状态:<span id="status">RUNNING</span></div>
    <button id="pauseBtn">暂停</button>
    <button id="resumeBtn">恢复</button>
</div>

<script>
    setInterval(() => {
        fetch('/upload/task/progress')
            .then(res => res.json())
            .then(data => {
                document.getElementById('progress').textContent = (data.progress * 100).toFixed(2) + '%';
                document.getElementById('status').textContent = data.status;
            });
    }, 1000);

    document.getElementById('pauseBtn').addEventListener('click', () => {
        fetch('/upload/task/pause', { method: 'POST' });
    });

    document.getElementById('resumeBtn').addEventListener('click', () => {
        fetch('/upload/task/resume', { method: 'POST' });
    });
</script>

关键注意事项

  • 大文件上传建议使用AWS SDK的分片上传(Multipart Upload),状态类中可记录已完成分片ID,恢复时直接续传,避免重复上传。
  • 若调度任务为一次性触发,可将@Scheduled改为@Async异步任务,状态控制逻辑保持一致。

内容的提问来源于stack exchange,提问作者7msseven

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 07:41:24