Frontend Lead · Rust Media Backend

Arthur Hovhannisyan

JavaScript frontend lead · Billups

Arthur is a Lead Software Engineer at Billups, previously at Evolution, who started his career as a backend developer at Alfa-Bank. His Rust project is a video processing service: an Axum backend that owns upload, inspection, and compression, with a Next.js client in front.

The decisions that matter are about resources and contracts. Uploads stream to disk and clean themselves up by ownership, ffmpeg runs as a supervised child process with a timeout and kill-on-drop, and a single OpenAPI spec generates the frontend types so the two sides cannot drift.

10+ yrs
Software engineering, from Alfa-Bank backend to frontend lead
4 min
Production release time after his CI/CD rebuild at Billups
99
Google Web Vitals score after a legacy frontend refactor
20+ teams
Using core UI libraries he optimized at Evolution
The challenge

Video is the worst-case payload

Videos are large, slow to process, and handled by external binaries Rust does not control. Buffering an upload in memory, leaking temp files on an error path, or leaving ffmpeg running after the client disconnects all turn into outages under load.

On top of that, a TypeScript frontend and a Rust backend evolve separately, and a silently drifting contract only shows up in production.

  • •Uploads of any size with flat memory usage
  • •No orphaned ffmpeg process or temp file, on success or failure
  • •Frontend types that cannot drift from the API
The outcome

A streaming media service with a typed contract

Arthur has a video processing service that streams uploads to disk, inspects them with ffprobe, compresses them under a supervised ffmpeg process, and streams the result back, with frontend types generated from the server's OpenAPI spec and a Docker, nginx, and GitHub Actions deployment around it.

He's still Lead Software Engineer at Billups, now with Rust backend work he can defend decision by decision: streaming I/O, process supervision, layered errors, and contract-first APIs.

  • ✓Resource cleanup owned by types, not by error paths
  • ✓ffprobe and ffmpeg integrated around how the tools actually read input
  • ✓A three-layer error model mapped cleanly onto HTTP
[ Uploads ]

Streaming uploads to disk, cleaned up by ownership

Axum multipart chunks are written from the network buffer straight to a file inside a per-request TempDir, removed on drop whether the request succeeds or fails. The filename is reduced with Path::file_name so a crafted name cannot escape the directory, the body limit comes from configuration, and empty payloads are rejected.

Memory stays flat regardless of video size, and there is no cleanup branch to forget: when the handler returns or errors, the temporary directory goes with it.

[ Inspection ]

Why ffprobe reads a file, not a pipe

The first version piped request chunks directly into ffprobe's stdin to skip the disk entirely. It lost context: container metadata often needs seeking, which a pipe cannot offer. Arthur went back to file-based inspection rather than forcing the streaming design.

ffprobe's JSON output is deserialized and mapped into a typed response, so the frontend receives a stable contract instead of raw tool output.

[ Process control ]

ffmpeg as a supervised child process

ffmpeg runs through tokio::process with kill_on_drop(true), -nostdin, and -progress pipe:2. Stderr is parsed for frame and fps progress, and wait() is wrapped in a Tokio timeout, so a hung encode or a dropped client request never leaves an orphaned process.

The compression preset is fixed in code: libx264 at CRF 23 with AAC audio at 128k. The output streams back through ReaderStream as an attachment carrying the original filename.

[ API contract ]

One OpenAPI spec, enforced across the stack

Routes are annotated with utoipa, and a dedicated openapi_generator binary emits the spec the frontend TypeScript types are generated from. A pre-push hook and CI fail on drift. Errors are layered: DomainError, ServerError, and an ApplicationError that maps onto HTTP responses.

Rate limiting through tower_governor keys on the real client IP behind nginx with SmartIpKeyExtractor, and is enabled only in production.

The journey

One clear path through the build

Drag to explore · Select a milestone to read the full story

Max Wells

Mentor perspective

Arthur Hovhannisyan tests his assumptions against the tools. Piping uploads straight into ffprobe looked cleaner on paper; when it lost container metadata, he went back to a seekable file instead of forcing it. The same instinct shows in how he runs ffmpeg: every process has an owner, a timeout, and a way to die.

Max Wells

Rustify mentor

Want results like Arthur's?

Max WellsAvailable for calls

Max Wells

Founder · Rustify

Book your Rust career diagnostic

30 minutes, 1:1 with Max. An honest read on where you are and whether Bootcamp or Mentorship fits, before you apply.

Only a few diagnostic slots left this week.

Applications are reviewed carefully.

← Back to case studies

More client journeys

See another path into Rust

Ready to Land a $80k+ Rust Job in the US or Europe?