Partitioned Processing with Checkpointing¶
This document describes DataJuicer’s fault-tolerant processing system with partitioning, checkpointing, and event logging.
Overview¶
The ray_partitioned executor splits datasets into partitions and processes them with configurable checkpointing. Failed jobs can resume from the last checkpoint.
Checkpointing strategies:
every_n_ops- checkpoint every N operations (default, balanced)every_op- checkpoint after every operation (max protection, impacts performance)manual- checkpoint only after specified operations (best for known expensive ops)disabled- no checkpointing (best performance)
Directory Structure¶
{work_dir}/{job_id}/
├── job_summary.json # Job metadata (created on completion)
├── events_{timestamp}.jsonl # Machine-readable event log
├── dag_execution_plan.json # DAG execution plan
├── checkpoints/ # Checkpoint data
│ ├── partitioning_info.json # Saved row boundaries and partition hashes
│ └── checkpoint_op_*.parquet/ # Per-operation partition checkpoints
├── partitions/ # Input partitions
├── logs/ # Human-readable logs
└── metadata/ # Job metadata
Configuration¶
Partition Modes¶
Auto mode (recommended) - analyzes data and resources to determine optimal partitioning:
executor_type: ray_partitioned
partition:
mode: "auto"
max_concurrent_partitions: "auto" # Resource-aware driver concurrency
target_size_mb: 256 # Target partition size (128, 256, 512, or 1024)
size: 5000 # Fallback if auto-analysis fails
max_size_mb: 256 # Fallback max size
Manual mode - specify exact partition count:
partition:
mode: "manual"
num_of_partitions: 8
max_concurrent_partitions: "auto"
max_concurrent_partitions: "auto" is the default. It is resolved after
operator resource planning: GPU pipelines use the tightest CPU/GPU worker
capacity reported by the Ray cluster, while CPU-only pipelines use a
conservative outer-pipeline cap of 4. The actual concurrency is also bounded by
the partition count and any explicit global actor num_proc budget. Set a
positive integer to override the automatic limit.
Checkpointing¶
checkpoint:
enabled: true
strategy: every_n_ops # every_n_ops (default), every_op, manual, disabled
n_ops: 5 # Default: checkpoint every 5 operations
op_names: # For manual strategy - checkpoint after expensive ops
- document_deduplicator
- embedding_mapper
When checkpointing is enabled, the initial run saves
checkpoints/partitioning_info.json. For every logical partition, this file
records:
start_row(inclusive) andend_row(exclusive) in the ordered input;the partition row count;
a stable hash of the complete partition contents;
the partition hash algorithm used by the writer.
These values allow an explicit resume to recreate the original logical partitions even when Ray produces a different physical block layout in the new process. Complete partition hashes are sensitive to row order, independent of Ray batch boundaries, and validated before any checkpoint is reused.
Intermediate Storage¶
intermediate_storage:
format: "parquet" # parquet, arrow, jsonl
compression: "snappy" # snappy, gzip, none
preserve_intermediate_data: true
retention_policy: "keep_all" # keep_all, keep_failed_only, cleanup_all
Usage¶
Running Jobs¶
# Auto partition mode
dj-process --config config.yaml --partition.mode auto
# Manual partition mode
dj-process --config config.yaml --partition.mode manual --partition.num_of_partitions 4
# Optional: start a new job with a custom job ID
dj-process --config config.yaml --job_id my_experiment_001
When checkpointing is enabled, a new ray_partitioned job prints a resume
token:
Resume token: 20260805_115141_81270d. Rerun the original command with
--resume 20260805_115141_81270d to resume this job.
Resuming Jobs¶
# Use the token printed by the initial run. Keep the input and recipe unchanged.
dj-process --config config.yaml --resume 20260805_115141_81270d
# A custom ID from the initial run can be used in the same way.
dj-process --config config.yaml --resume my_experiment_001
--resume is supported only by the ray_partitioned executor. It performs a
strict resume in the following order:
locate the original work and checkpoint directories;
verify that the current configuration matches the original run;
load the saved partition count, row boundaries, and content hashes;
recreate the original partitions with the saved row boundaries;
validate every complete partition hash;
load completed checkpoints and process only the unfinished work.
If metadata is missing, row boundaries are invalid, the input has changed, or a content hash does not match, explicit resume stops with an error and leaves the existing checkpoints unchanged.
--job_id remains available for custom job naming and backward compatibility.
For fault-tolerant continuation, prefer --resume: the legacy --job_id
resumption path keeps its previous behavior and may clear mismatched
checkpoints before starting fresh. Metadata created by an older Data-Juicer
version can still be read, but it does not contain the row boundaries and full
content hashes required by explicit resume; --resume therefore rejects it
without deleting its checkpoints.
If both arguments are supplied, their values must be identical:
dj-process --config config.yaml \
--job_id my_experiment_001 \
--resume my_experiment_001
Checkpoint Strategies¶
# Every operation
dj-process --config config.yaml --checkpoint.strategy every_op
# Every N operations
dj-process --config config.yaml --checkpoint.strategy every_n_ops --checkpoint.n_ops 3
# Manual
dj-process --config config.yaml --checkpoint.strategy manual --checkpoint.op_names op1,op2
Auto-Configuration¶
In auto mode, the optimizer:
Samples the dataset to detect modality (text, image, audio, video, multimodal)
Measures memory usage per sample
Analyzes pipeline complexity
Calculates partition size targeting the configured
target_size_mb
Default partition sizes by modality:
Modality |
Default Size |
Max Size |
Memory Multiplier |
|---|---|---|---|
Text |
10000 |
50000 |
1.0x |
Image |
2000 |
10000 |
5.0x |
Audio |
1000 |
4000 |
8.0x |
Video |
400 |
2000 |
20.0x |
Multimodal |
1600 |
6000 |
10.0x |
Job Management Utilities¶
Monitor¶
# Show progress
python -m data_juicer.utils.job.monitor {job_id}
# Detailed view
python -m data_juicer.utils.job.monitor {job_id} --detailed
# Watch mode
python -m data_juicer.utils.job.monitor {job_id} --watch --interval 10
from data_juicer.utils.job.monitor import show_job_progress
data = show_job_progress("job_id", detailed=True)
Stopper¶
# Graceful stop
python -m data_juicer.utils.job.stopper {job_id}
# Force stop
python -m data_juicer.utils.job.stopper {job_id} --force
# List running jobs
python -m data_juicer.utils.job.stopper --list
from data_juicer.utils.job.stopper import stop_job
stop_job("job_id", force=True, timeout=60)
Common Utilities¶
from data_juicer.utils.job.common import JobUtils, list_running_jobs
running_jobs = list_running_jobs()
job_utils = JobUtils("job_id")
summary = job_utils.load_job_summary()
events = job_utils.load_event_logs()
Event Types¶
job_start,job_complete,job_failedpartition_start,partition_complete,partition_failedop_start,op_complete,op_failedcheckpoint_save,checkpoint_load
Performance Considerations¶
Checkpoint vs Ray Optimization Trade-off¶
Key insight: Checkpointing interferes with Ray’s automatic optimization.
Ray optimizes execution by fusing operations together and pipelining data. Each checkpoint forces materialization, which breaks the optimization window:
Without checkpoints: op1 → op2 → op3 → op4 → op5
|___________________________|
Ray optimizes entire window
With every_op: op1 | op2 | op3 | op4 | op5
materialize at each | (5 barriers)
With every_n_ops(5): op1 → op2 → op3 → op4 → op5 |
|_____________________________|
Ray optimizes all 5 ops
Checkpoint Cost Analysis¶
Cost Type |
Typical Value |
|---|---|
Checkpoint write |
~2-5 seconds |
Cheap op execution |
~1-2 seconds |
Expensive op execution |
minutes to hours |
For cheap operations, checkpointing costs MORE than re-running on failure.
Example pipeline analysis:
filter(1s) → mapper(2s) → deduplicator(300s) → filter(1s)
Strategy | Overhead | Protection Value
-----------------|-----------|------------------
every_op | ~20s | Save 1-304s on failure
after dedup only | ~5s | Save 300s on failure
disabled | 0s | Re-run everything
Strategy Recommendations¶
Job Duration |
Recommended Strategy |
Rationale |
|---|---|---|
< 10 min |
|
Re-running is cheap |
10-60 min |
|
Balanced protection |
> 60 min with expensive ops |
|
Checkpoint after expensive ops only |
Unstable infrastructure |
|
Accept overhead for reliability |
Operation Categories¶
Expensive operations (checkpoint after these):
*_deduplicator- Global state, expensive computation*_embedding_*- Model inference*_model_*- Model inference*_vision_*- Image/video processing*_audio_*- Audio processing
Cheap operations (skip checkpointing):
*_filter- Simple filteringclean_*- Text cleaningremove_*- Field removal
Storage Recommendations¶
Event logs: fast storage (SSD)
Checkpoints: large capacity storage
Partitions: local storage
Partition Sizing Trade-offs¶
Smaller partitions: better fault tolerance, more scheduling overhead
Larger partitions: less overhead, coarser recovery granularity
Troubleshooting¶
Job resumption fails:
ls -la ./outputs/{work_dir}/{job_id}/job_summary.json
ls -la ./outputs/{work_dir}/{job_id}/checkpoints/
cat ./outputs/{work_dir}/{job_id}/checkpoints/partitioning_info.json
Use the resume token printed by the original run and rerun the same recipe with
--resume. Check the error log for configuration mismatch, missing partition
metadata, invalid row boundaries, or partition content hash mismatch. Explicit
resume does not delete checkpoints when validation fails.
Check Ray status:
ray status
View logs:
cat ./outputs/{work_dir}/{job_id}/events_*.jsonl
tail -f ./outputs/{work_dir}/{job_id}/logs/*.txt