There is no problem not worth solving, and no technology not worth learning!

Export progress is adjusted to the rules shown in Excel’s actual export progress

现在的 Excel 导出进度是由前端自行显示的,并未受到后端的控制

1. The current Excel export progress is displayed by the front-end and is not controlled by the back-end. as shown in Figure 1

现在的 Excel 导出进度是由前端自行显示的,并未受到后端的控制
Figure 1

The decision is adjusted to display according to the actual export progress of Excel, and the final implementation rules are as follows:
Now exporting the Excel file, generally speaking, after the backend receives the front-end request, there are a total of 4 steps:
(1) Queue in the queue. In this link, the front-end progress always shows 0%
(2) Then when the queue job really starts, if the Excel is 10,000 rows, the progress increases by 9.9% for every 1000 rows written. When the write is complete, the progress is 99%
(3) Then it involves the processing of some column formats of Excel files, as well as uploading files to the cloud, generating download links, etc. After this link is completed, the front-end display progress is 100%
(4) After the front end obtains the download link, the download is successful. In this link, the progress is no longer displayed.

3. The final code implementation is roughly as follows



    private string $cachedProgressPercentKey = 'job_status:progress_percent'; // 进度百分比的缓存键
    private int $cachedProgressPercentTtl = 24 * 3600; // 进度百分比的缓存过期时间

    public const EXPORT_EXCEL_WRITE_PROGRESS_PERCENT = 99; // 导出 Excel 时写入文件所占用的百分比

    private int $exportExcelMaxCount = 100000; // 限制最大导出行数为 100000
    private int $exportExcelChunkCount = 1000; // 导出时分块数量为 1000


	// 更新进度百分比
	$orderShippingLogCount = min($orderShippingLogQueryBuilder->count(), $this->exportExcelMaxCount);
	$chunkCount = (int)ceil($orderShippingLogCount / $this->exportExcelChunkCount); // 上舍入
	$i = 0;
	$uid = $jobStatus->uid;
	Log::info(
		'$orderShippingLog',
		[
			'$orderShippingLogCount' => $orderShippingLogCount,
			'$chunkCount' => $chunkCount,
		]
	);
	$orderShippingLogQueryBuilder->chunk($this->exportExcelChunkCount, function ($orderShippingLogs) use ($params, $excel, $columns, $chunkCount, $uid, &$i) {
		// 限制最大导出行数为 100000
		if ($i >= $chunkCount) {
			return false;
		}

		$data = [];

		foreach ($orderShippingLogs as $rowKey => $orderShippingLog) {
			$data[] = static::toResource($orderShippingLog, $params['timezone']);
		}
		$excel->writeRows($data);

		// 更新进度百分比
		$i++;
		$progressPercent = ($i / $chunkCount) * JobStatusService::EXPORT_EXCEL_WRITE_PROGRESS_PERCENT;
		app(JobStatusService::class)->setProgressPercent($uid, $progressPercent);

		Log::info(
			'$orderShippingLogChunk',
			[
				'$i' => $i,
				'$chunkCount' => $chunkCount,
				'$progressPercent' => $progressPercent
			]
		);

		return true;
	});

	// 更新进度百分比
	$jobStatusService->setProgressPercent($this->jobStatus->uid, 100);



    /**
     * 设置进度百分比
     * @param string $uid
     * @param float $progressPercent
     * @return void
     */
    public function setProgressPercent(string $uid, float $progressPercent): void
    {
        $cachedKey = sprintf($this->cachedProgressPercentKey . ':%s', $uid);
        Cache::store('redis')->put($cachedKey, round($progressPercent, 2), $this->cachedProgressPercentTtl);
    }

    /**
     * 获取进度百分比
     * @param string $uid
     * @return float
     * @throws InvalidArgumentException
     */
    private function getProgressPercent(string $uid): float
    {
        $cachedKey = sprintf($this->cachedProgressPercentKey . ':%s', $uid);
        $cachedProgressPercent = Cache::store('redis')->get($cachedKey);

        if (!$cachedProgressPercent) {
            return 0;
        }

        return (float)$cachedProgressPercent;
    }


4. The log printing is as follows:


[2024-05-10 07:33:35] local.INFO: $orderShippingLog {"$orderShippingLogCount":4696,"$chunkCount":5} 
[2024-05-10 07:33:37] local.INFO: $orderShippingLogChunk {"$i":1,"$chunkCount":5,"$progressPercent":19.8} 
[2024-05-10 07:33:40] local.INFO: $orderShippingLogChunk {"$i":2,"$chunkCount":5,"$progressPercent":39.6} 
[2024-05-10 07:33:41] local.INFO: $orderShippingLogChunk {"$i":3,"$chunkCount":5,"$progressPercent":59.4} 
[2024-05-10 07:33:42] local.INFO: $orderShippingLogChunk {"$i":4,"$chunkCount":5,"$progressPercent":79.2} 
[2024-05-10 07:33:43] local.INFO: $orderShippingLogChunk {"$i":5,"$chunkCount":5,"$progressPercent":99} 


5. The interface response structure is as follows


{
    "label": "order",
    "type": "export",
    "status": "pending",
    "file_path": "",
    "progress_percent": 59.4
}


Need long-term technical maintenance or remote troubleshooting?

I am a PHP / Go backend engineer with 15+ years of experience, focused on existing system maintenance, bug fixing, performance optimization, server troubleshooting, WordPress maintenance, and small feature iterations.

If your project is facing any of the following issues, we can start with a small troubleshooting task first:

  • ✅ PHP / Laravel / Yii2 legacy systems without active maintenance
  • ✅ Go / Gin backend APIs that need troubleshooting or optimization
  • ✅ Slow, broken, or unstable WordPress websites
  • ✅ Nginx / MySQL / Redis / Linux server issues
  • ✅ CDN / Cloudflare / DNS / HTTPS configuration problems
  • ✅ Long-term remote technical support or part-time maintenance

More details: About Me & Collaboration

WeChat: 13980074657
Email: shuijingwanwq@gmail.com
Telegram: @shuijingwan
GitHub: https://github.com/shuijingwan

评论

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.