Software Architect · Rust Systems

Andrés Gutiérrez Ramírez

Senior software architect · backend systems · 10+ yrs

“Rust is a breath of fresh air, it removes a lot of the problems with garbage collection, ownership, global scope.”

Andrés is a senior software engineer and architect with a background in backend development, DevOps, clean architecture and team training. He is building crabhive, a bounded telemetry pipeline in Rust 2024 and Tokio, rebuilt from the shape of an earlier log collector he wrote in Node.js.

The goal is one small, finished async subsystem rather than a large unfinished one. The first phases cover sampling, a bounded ingress that sheds load, clean shutdown and a read model. A ratatui dashboard, HTTP ingest and SQLite persistence are planned next, not presented as finished work.

10+ yrs
Software engineering and architecture
Architect
Clean architecture and system design
DevOps
Backend and infrastructure ownership
Mentor
Technical training and team transformation
The challenge

Backpressure you can prove, not assume

In Node.js, an ingest pipeline tends to buffer until memory runs out, and nobody notices until production. Rust forces the questions up front: who owns each event, which thread does blocking work, what happens when the queue is full, and how the system shuts down without losing data.

Andrés wanted every one of those answers encoded in types and tests, not in a comment. That means testing the failure path directly, including a queue filled on purpose.

  • •Blocking sampling must stay off the async runtime
  • •A slow consumer must never grow memory
  • •Shutdown must drain, then report what it drained
The outcome so far

crabhive: bounded by construction

The pipeline samples on its own thread, admits through a bounded channel, sheds load on a full queue and drains cleanly on Ctrl-C. A read model keeps bounded history ready for the dashboard.

Every non-obvious choice, from the mutex over ArcSwap to the cumulative CPU counter, has a written reason and a trigger for revisiting it.

  • ✓Dedicated sampler thread and Tokio consumer
  • ✓Bounded mpsc with tested load shedding
  • ✓Deferred decisions register with hard and soft windows
[ Ingress ]

A full queue sheds load instead of blocking the sampler

CPU and memory are sampled on a dedicated OS thread, because reading /proc is blocking work that does not belong on the async runtime. Each reading goes into a bounded mpsc channel with try_send, and a Tokio task drains it.

On TrySendError::Full the event is dropped with a warning and the sampler keeps its cadence. Memory stays flat no matter how slow the consumer gets, and a dedicated test fills the channel on purpose to prove the sampler never panics or stalls.

[ Shutdown ]

Stopping is a chain of ownership, not a kill switch

Ctrl-C flips an AtomicBool. The sampler exits its loop and drops its Sender, which closes the channel, which ends the consumer once the queue is drained. The final processed count is a real drain, not an estimate.

Polling a flag means stopping can take one sample interval, an accepted cost until a later phase brings proper cancellation. The same rigor applies to the data: Linux exposes cumulative counters in /proc/stat, so the first CPU reading is an average since boot, and the next slice primes and discards it instead of reporting it.

[ Read model ]

A mutex, chosen on purpose over lock-free

The worker folds events into a Snapshot whose histories are VecDeques preallocated to a fixed length: push at the back, evict at the front, never reallocate. Readers share it through Arc<Mutex<Snapshot>>.

ArcSwap or a triple buffer were considered and rejected for now: with one writer and two readers at 5 Hz, a lock held for a single push_back wins, while publish-latest primitives would clone the whole snapshot per event. The trigger to revisit is written down: many concurrent metrics scrapers, and if the lock gets hot first, batching with recv_many comes before a new primitive.

[ Decisions ]

Deferred decisions with explicit triggers

Open questions live in a deferred decisions register, each with the event that forces it and whether its window is soft or hard. Adding #[non_exhaustive] to public enums, for example, must happen before the first cargo publish, or a new variant silently becomes a breaking change.

The same discipline covers quality gates: cargo fmt, clippy with -D warnings, nextest and cargo doc with -D warnings run identically in a pre-push hook and in CI, because a local gate that disagrees with CI teaches you to trust a result that does not bind.

The journey

One clear path through the build

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

Max Wells

Mentor perspective

Andrés brings a rare combination to a Rust transition: deep experience in architecture and debugging complex systems, plus a strong need to understand the machinery underneath. What stands out is his restraint: he picked a mutex over a lock-free primitive with the numbers to back it, and wrote down exactly when that choice stops being right. That is how senior systems engineers think.

Max Wells

Rustify mentor

Want results like Andrés'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?