Analytics reporting workflow fails to export large datasets to cloud storage on timeout

We have an automated analytics reporting workflow in AEC 2022 that exports large datasets (500k-2M rows) to Azure Blob Storage for downstream data warehouse integration. The workflow runs nightly to export the previous day’s customer interaction data, but it consistently fails when datasets exceed approximately 1M rows.

The failure occurs during the export step with a timeout error. The workflow successfully generates the report and begins the export, but when transferring large files (>500MB) to cloud storage, the Azure API call times out and the workflow fails. This leaves us with incomplete data in our warehouse.

Here’s the error from the logs:


ERROR: Export operation timed out after 300 seconds
ERROR: Azure Blob Storage upload failed for file: analytics_export_2025-07-10.csv
ERROR: Uploaded 387MB of 623MB before timeout
WARN: Workflow execution failed at step: CloudStorageExport

Our export timeout is configured to 300 seconds (5 minutes), and the cloud storage API limits appear to be around 10GB per request, so we’re well within limits. The issue seems to be that single-threaded uploads of large files take too long. How can we configure proper data chunking strategy to handle these large exports without timing out?

Your export timeout failures are caused by inefficient single-file upload strategy and inadequate timeout configuration for large dataset transfers. I’ll provide a comprehensive solution addressing all three focus areas to ensure reliable exports of large analytics datasets.

Export Timeout Configuration: The 300-second timeout is insufficient for large file uploads, especially considering network variability and cloud storage API overhead. Reconfigure your workflow timeouts at multiple levels:

First, increase the workflow step timeout to allow for large transfers:

Workflow Definition > Export Step > Timeout: 3600 seconds (1 hour)

Workflow Definition > Export Step > Retry on Timeout: Enabled

Workflow Definition > Export Step > Max Retries: 3

Second, configure the Azure SDK timeout settings in your cloud storage integration:

azure.storage.upload.timeout=1800000
azure.storage.connection.timeout=60000
azure.storage.read.timeout=300000

Upload timeout of 30 minutes allows for complete transfer of large files. Connection timeout of 60 seconds handles initial connection establishment. Read timeout of 5 minutes handles Azure API response delays.

Third, implement adaptive timeout calculation based on file size:

long fileSize = exportFile.length();
long estimatedUploadTime = (fileSize / 1024 / 1024) * 2; // 2 seconds per MB
long timeout = Math.max(600, estimatedUploadTime * 2); // Minimum 10 min, 2x estimated time
uploadClient.setTimeout(timeout);

This dynamically adjusts timeout based on actual file size, preventing timeouts on legitimately large transfers while still catching stuck uploads.

Data Chunking Strategy: Replace the single-file upload approach with Azure’s block blob multipart upload for dramatically improved performance and reliability:

Implement block-based upload in your workflow:

BlobClient blobClient = containerClient.getBlobClient(fileName);
BlockBlobClient blockBlobClient = blobClient.getBlockBlobClient();

long blockSize = 8 * 1024 * 1024; // 8MB blocks
List<String> blockIds = new ArrayList<>();

try (FileInputStream fis = new FileInputStream(exportFile)) {
  int blockNum = 0;
  byte[] buffer = new byte[(int)blockSize];
  int bytesRead;

  while ((bytesRead = fis.read(buffer)) > 0) {
    String blockId = Base64.getEncoder().encodeToString(
      String.format("block-%05d", blockNum++).getBytes()
    );

    blockBlobClient.stageBlock(blockId,
      new ByteArrayInputStream(buffer, 0, bytesRead), bytesRead);
    blockIds.add(blockId);
  }

  blockBlobClient.commitBlockList(blockIds);
}

This splits the file into 8MB blocks and uploads them sequentially. Each block upload has its own timeout, so a timeout only affects one block rather than the entire file.

For even better performance, implement parallel block uploads:

ExecutorService executor = Executors.newFixedThreadPool(4);
List<Future<String>> futures = new ArrayList<>();

for (int i = 0; i < totalBlocks; i++) {
  final int blockNum = i;
  futures.add(executor.submit(() -> {
    String blockId = generateBlockId(blockNum);
    byte[] blockData = readBlock(exportFile, blockNum, blockSize);
    blockBlobClient.stageBlock(blockId,
      new ByteArrayInputStream(blockData), blockData.length);
    return blockId;
  }));
}

List<String> blockIds = futures.stream()
  .map(f -> f.get())
  .collect(Collectors.toList());

blockBlobClient.commitBlockList(blockIds);
executor.shutdown();

This uploads 4 blocks in parallel, reducing total upload time by approximately 75% for large files.

Cloud Storage API Limits: Optimize your workflow to work within Azure’s throughput limits and implement proper error handling:

First, implement compression before upload to reduce data transfer volume:

File compressedFile = new File(exportFile.getPath() + ".gz");
try (FileInputStream fis = new FileInputStream(exportFile);
     FileOutputStream fos = new FileOutputStream(compressedFile);
     GZIPOutputStream gzos = new GZIPOutputStream(fos)) {
  byte[] buffer = new byte[8192];
  int len;
  while ((len = fis.read(buffer)) > 0) {
    gzos.write(buffer, 0, len);
  }
}

CSV files typically compress to 15-25% of original size, dramatically reducing upload time and bandwidth costs.

Second, implement file partitioning for datasets exceeding 1M rows:

Workflow Configuration > Export Settings > Partition Strategy: Time-based

Workflow Configuration > Export Settings > Partition Size: 250000 rows

Workflow Configuration > Export Settings > Parallel Uploads: 3

This creates multiple smaller files (approximately 150MB each when compressed) that can be uploaded in parallel. Configure the workflow to track completion of all partitions:

List<String> partitionFiles = partitionDataset(exportData, 250000);
List<CompletableFuture<Void>> uploadFutures = partitionFiles.stream()
  .map(file -> CompletableFuture.runAsync(() -> uploadToAzure(file)))
  .collect(Collectors.toList());

CompletableFuture.allOf(uploadFutures.toArray(new CompletableFuture[0])).join();

Third, implement retry logic with exponential backoff for transient Azure API failures:

int maxRetries = 3;
int retryDelay = 1000;

for (int attempt = 0; attempt < maxRetries; attempt++) {
  try {
    blockBlobClient.stageBlock(blockId, blockData, blockSize);
    break;
  } catch (StorageException e) {
    if (attempt == maxRetries - 1) throw e;
    Thread.sleep(retryDelay * (1 << attempt)); // Exponential backoff
  }
}

Finally, monitor Azure storage account metrics to detect throttling:

Azure Portal > Storage Account > Metrics > Add Metric: “Throttling Errors”

Alert Rule: If throttling errors > 10 in 5 minutes, notify operations team

If you’re consistently hitting throttling limits, consider upgrading your Azure Storage account tier or implementing rate limiting in your workflow to stay within Azure’s throughput targets (approximately 20,000 requests per second for standard accounts).

Implement progress tracking and resumable uploads to handle partial failures:

String checkpointFile = exportFile.getPath() + ".checkpoint";
Set<String> completedBlocks = loadCheckpoint(checkpointFile);

for (int i = 0; i < totalBlocks; i++) {
  String blockId = generateBlockId(i);
  if (completedBlocks.contains(blockId)) continue;

  uploadBlock(blockId, blockData);
  completedBlocks.add(blockId);
  saveCheckpoint(checkpointFile, completedBlocks);
}

This allows the workflow to resume from the last successfully uploaded block if a timeout occurs, rather than restarting the entire upload.

After implementing these changes, your workflow will reliably export datasets of 2M+ rows. The combination of compression (reducing file size by 75-85%), parallel block uploads (reducing upload time by 70-80%), and proper timeout configuration (allowing up to 1 hour for large transfers) ensures exports complete successfully even for the largest datasets. Monitor the workflow execution logs to verify block uploads are completing successfully and total export time is within acceptable limits for your nightly processing window.


This draft is based on general Adobe Experience Cloud knowledge. It has not been verified against your specific version and environment. Practitioners: verify the steps and share your experience below.

Azure Blob Storage supports block-based uploads that are much more efficient for large files. Instead of uploading the entire file in one request, split it into blocks (typically 4-8MB each) and upload them in parallel. The Azure SDK has built-in support for this - you just need to configure your workflow to use block blob upload mode instead of single-blob mode.

Consider implementing incremental exports instead of full daily exports. If you’re exporting 1-2M rows daily, you’re probably re-exporting a lot of unchanged data. Configure your workflow to track the last successful export timestamp and only export records modified since then. This dramatically reduces dataset size and export time. You can use CDC (change data capture) patterns to identify changed records efficiently.

The 300-second timeout is too aggressive for large file uploads over the network. Increase it to at least 1800 seconds (30 minutes) to allow for network variability and large transfers. Also implement retry logic with exponential backoff - if a block upload fails, retry that specific block rather than failing the entire workflow. AEC 2022’s workflow engine supports partial completion tracking for exactly this scenario.

Split your export into multiple smaller files rather than one large file. Configure the workflow to partition the dataset by hour or by customer segment, creating multiple 100-200MB files instead of one 600MB file. This has several benefits: faster individual uploads, ability to parallelize uploads, and easier recovery if one partition fails. Your downstream warehouse can easily handle multiple files per day.

Check your Azure Blob Storage account configuration - you might be hitting throttling limits rather than timeout limits. Azure has per-account and per-blob throughput limits that can cause slowdowns during large uploads. Look at your storage account metrics to see if you’re being throttled. Consider using Azure Data Lake Storage Gen2 instead of standard Blob Storage for better performance with large analytics datasets.

Implement compression before upload. A 623MB CSV file can typically compress to 100-150MB with gzip compression, dramatically reducing upload time. The decompression overhead in your data warehouse is minimal compared to the time saved on upload. Configure your workflow to compress the export file before initiating the cloud storage upload.