Goal: A video is uploaded, processed, and becomes streamable with no failures. Actors
- Client (Web/Mobile)
- Upload Service (TUS)
- Metadata Service
- Temporal Workflow Engine
- Transcoding Worker (FFmpeg)
- Object Storage (MinIO)
- Streaming Gateway (HLS)
- Cache (Varnish)
-
Client initializes upload
- Client requests a TUS upload session
- Upload Service creates
upload_id - Upload metadata persisted:
upload_id status = UPLOADING bytes_uploaded = 0
-
Client uploads video chunks
- Chunks are appended to a temporary object in MinIO
- Upload Service tracks offset
-
Upload completes
- Checksum verified
- Temporary object finalized
- Upload state:
status = UPLOADED
-
Video metadata created
- Metadata Service creates
video_id - Associates:
upload_id -> video_id video_state = CREATED
- Metadata Service creates
-
Workflow started
- Metadata Service triggers Temporal workflow:
VideoProcessingWorkflow(video_id)
- Video state:
PROCESSING
- Metadata Service triggers Temporal workflow:
-
Transcoding activities
- Workflow schedules activities:
- Transcode 360p
- Transcode 720p
- Transcode 1080p
- Each output written to MinIO
- Workflow schedules activities:
-
HLS generation
- Per-rendition playlists generated
- Master playlist generated
-
Video becomes playable
- Metadata updated:
video_state = READY
- Metadata updated:
-
Client plays video
- Client fetches master playlist
- Segments delivered via Varnish
- Upload ≠ Video
- Video exists only after upload completes
- Workflow owns processing, not APIs
Goal: System remains correct under partial failure.
This flow is what makes Vora impressive.
-
Client starts upload
upload_state = UPLOADING -
Network dies at 40%
- Upload Service remains idle
- Partial data preserved
-
Client reconnects
- Uses same
upload_id - Upload resumes from last offset
- Uses same
-
Upload completes
upload_state = UPLOADED
✅ No duplicate uploads ✅ No corrupted data
-
Workflow is running
video_state = PROCESSING -
360p completed successfully
-
720p transcoding crashes
-
Temporal detects activity failure
- Retry policy triggers
- Only failed rendition retried
-
System state:
renditions: 360p = DONE 720p = RETRYING 1080p = PENDING
-
Retry succeeds
-
Workflow continues
-
Video transitions to:
READY
✅ No duplicate transcoding ✅ Work is not redone ✅ Exactly-once semantics via idempotency
- Temporal crashes / restarts
- Workflow state replayed
- Completed activities are skipped
- In-progress activities resumed
✅ State recovered without manual intervention
- Transcoding activity fails
- Activity retries with backoff
- Workflow pauses, not corrupted
- All activities are idempotent
- Workflow state is authoritative
- Partial success is tracked explicitly
Goal: High-throughput playback with observability.
- Client
- Streaming Gateway
- Varnish
- MinIO
- Analytics Ingestor
- ClickHouse
-
Client requests master playlist
- Streaming Gateway receives request
- Varnish cache checked
-
Cache behavior
- Cache HIT → served immediately
- Cache MISS → fetched from MinIO, cached
-
Client requests video segments
- Same cache logic applies
- Majority of traffic should be cache hits
-
Playback events emitted
- Client emits:
play pause segment_fetched watch_time bitrate_selected
- Client emits:
-
Analytics ingestion
- Events sent asynchronously
- Playback is never blocked
-
Analytics storage
- Events stored in ClickHouse
- Partitioned by time + video_id
-
Analytics queries
- Drop-off per segment
- Average watch time
- Bitrate distribution
- Playback path is read-only
- Analytics is event-driven
- Cache drastically reduces origin load
CREATED → UPLOADING → UPLOADED → FAILEDCREATED
→ PROCESSING
→ PARTIALLY_READY
→ READY
→ FAILEDPENDING → PROCESSING → DONE → FAILED