Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Core Terms and Verbal Models

This chapter replaces the old "pattern" section with something more fundamental.

Instead of compressing the problems into code-first patterns, this chapter starts with the words themselves:

  • what they mean in ordinary English
  • what they mean in computer science
  • what role they play in the backend problems

The goal is to make the terms themselves feel natural before turning them into data structures or Rust code.

Problem-to-Term Map

Rate limiter

Core terms:

  • rate
  • limit
  • key
  • window
  • counter
  • request
  • allow / reject
  • token

Worker pool / job queue

Core terms:

  • worker
  • pool
  • job
  • queue
  • dispatch
  • shutdown
  • backpressure

In-memory cache

Core terms:

  • cache
  • key
  • value
  • hit
  • miss
  • eviction
  • expiration

Event bus / pub-sub

Core terms:

  • event
  • bus
  • publish
  • subscribe
  • broadcast
  • consumer
  • producer

Retry queue / scheduler

Core terms:

  • retry
  • delay
  • schedule
  • backoff
  • failure
  • dead letter

Metrics aggregator

Core terms:

  • metric
  • count
  • average
  • bucket
  • rolling window
  • aggregation

Connection pool

Core terms:

  • connection
  • pool
  • acquire
  • release
  • timeout
  • capacity

LRU cache

Core terms:

  • recent
  • usage
  • eviction
  • capacity
  • ordering

Token bucket

Core terms:

  • token
  • bucket
  • refill
  • consume
  • burst
  • rate

Log batcher

Core terms:

  • batch
  • buffer
  • flush
  • threshold
  • latency
  • throughput

Core Term Explanations

Queue

Simple English:

A queue is a line. Things join at the back and leave from the front.

Computer science meaning:

A queue is an ordered data structure that usually follows first-in, first-out behavior.

Why it matters here:

  • worker pools consume queued jobs
  • schedulers hold pending work in order
  • buffered systems queue items before processing

Rust type references:

  • std::collections::VecDeque is the most direct general-purpose queue type in Rust

  • std::collections::VecDeque<T> shows the type parameter: the element type T stored in the deque

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::collections::VecDeque;
    let mut queue: VecDeque<Job> = VecDeque::new();
    }
  • std::sync::mpsc::channel creates a multi-producer, single-consumer channel for threaded code

  • std::sync::mpsc::Sender<T> and std::sync::mpsc::Receiver<T> show the message type parameter

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::sync::mpsc::{channel, Sender, Receiver};
    let (tx, rx): (Sender<Job>, Receiver<Job>) = channel();
    }
  • std::sync::mpsc::sync_channel is the bounded threaded version with backpressure

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::sync::mpsc::{sync_channel, SyncSender};
    let (tx, rx): (SyncSender<Job>, Receiver<Job>) = sync_channel(100);
    }
  • tokio::sync::mpsc is the async queue/channel family

  • tokio::sync::mpsc::Sender<T> and tokio::sync::mpsc::Receiver<T> for async tasks

  • Example binding:

    #![allow(unused)]
    fn main() {
    use tokio::sync::mpsc::{channel, Sender, Receiver};
    let (tx, mut rx): (Sender<Job>, Receiver<Job>) = channel(100);
    }

Key methods (VecDeque):

  • VecDeque::new() creates an empty double-ended queue
  • queue.push_back(item) adds an item to the back of the queue
  • queue.push_front(item) adds an item to the front of the queue
  • queue.pop_front() removes and returns Option<T> from the front
  • queue.pop_back() removes and returns Option<T> from the back
  • queue.front() returns Option<&T> referencing the front element
  • queue.back() returns Option<&T> referencing the back element
  • queue.len() returns the number of elements
  • queue.is_empty() returns true if the queue has no elements
  • queue.clear() removes all elements

Key methods (channels - threaded):

  • channel() creates an unbounded channel, returns (Sender<T>, Receiver<T>)
  • sync_channel(capacity) creates a bounded channel, returns (SyncSender<T>, Receiver<T>)
  • sender.send(value) sends a value, returns Result<(), SendError<T>>
  • receiver.recv() blocks until a message arrives, returns Result<T, RecvError>
  • receiver.try_recv() tries to receive without blocking, returns Result<T, TryRecvError>
  • receiver.timeout_recv(duration) receives with a timeout

Key methods (channels - async):

  • channel(capacity) creates a bounded async channel, returns (Sender<T>, Receiver<T>)
  • sender.send(value).await sends a value asynchronously
  • receiver.recv().await receives a value asynchronously
  • receiver.try_recv() tries to receive without waiting
  • sender.closed() returns true if the channel is closed

Refined phrasing:

The Rust type system gives us queue-shaped types for different delivery models. VecDeque<T> is the direct data-structure queue, while channels model queued work that moves between producers and consumers.

Channel

Simple English:

A channel is a delivery path between one part of a system and another.

Computer science meaning:

A channel is a typed communication primitive with sender and receiver endpoints. It is commonly used to move values safely between threads or async tasks, often with queue semantics.

Why it matters here:

  • worker pools use channels to hand jobs from producers to workers
  • event systems use channels to move messages between components
  • bounded channels make capacity visible and can apply backpressure
  • channels decouple submission of work from processing of work

Rust type references:

  • std::sync::mpsc::channel creates a multi-producer, single-consumer channel for threaded code

  • std::sync::mpsc::Sender<T> and std::sync::mpsc::Receiver<T> show the message type parameter

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::sync::mpsc::{channel, Sender, Receiver};
    let (tx, rx): (Sender<Job>, Receiver<Job>) = channel();
    }
  • std::sync::mpsc::sync_channel creates a bounded channel with backpressure

  • std::sync::mpsc::SyncSender<T> and std::sync::mpsc::Receiver<T> for the bounded version

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::sync::mpsc::{sync_channel, SyncSender, Receiver};
    let (tx, rx): (SyncSender<Job>, Receiver<Job>) = sync_channel(100);
    }
  • tokio::sync::mpsc::channel creates an async multi-producer, single-consumer channel for Tokio tasks

  • tokio::sync::mpsc::Sender<T> and tokio::sync::mpsc::Receiver<T> show the message type parameter

  • Example binding:

    #![allow(unused)]
    fn main() {
    use tokio::sync::mpsc::{channel, Sender, Receiver};
    let (tx, mut rx): (Sender<Job>, Receiver<Job>) = channel(100);
    }

Refined phrasing:

A channel is a typed, concurrency-safe delivery boundary. In Rust, channels are how you move ownership of work or messages between producers and consumers without sharing mutable state directly.

A channel is not identical to a queue. A queue is the storage part; the channel is the full communication abstraction built around that queued storage.

  • std::collections::VecDeque<T>: "here is a queue of values"
  • tokio::sync::mpsc::channel<T>(N): "here is a concurrent typed delivery mechanism whose internal pending messages behave like a bounded queue"

Worker

Simple English:

A worker is something that performs tasks.

Computer science meaning:

A worker is an execution unit, often a thread or task, that repeatedly pulls work and processes it.

Why it matters here:

  • worker pools separate submission of work from execution of work

Rust type references:

  • std::thread::JoinHandle<T> represents a spawned thread in threaded code

  • std::thread::JoinHandle<T> shows the type parameter: the return type T from the thread

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::thread::{self, JoinHandle};
    let handle: JoinHandle<Result> = thread::spawn(|| { /* work */ });
    }
  • tokio::task::JoinHandle<T> represents a spawned async task

  • Example binding:

    #![allow(unused)]
    fn main() {
    use tokio::task::JoinHandle;
    let handle: JoinHandle<Result> = tokio::spawn(async move { /* work */ });
    }
  • Worker logic commonly loops over a std::sync::mpsc::Receiver<T> or std::collections::VecDeque<T>

  • Example: while let Some(job) = rx.recv() { /* process job */ }

Pool

Simple English:

A pool is a managed collection of reusable things.

Computer science meaning:

A pool is a bounded or managed set of resources that can be acquired and returned.

Why it matters here:

  • connection pools reuse expensive resources
  • worker pools reuse execution units

Rust type references:

  • Pools are often custom structs containing std::vec::Vec<T>, std::collections::VecDeque<T>, or a semaphore plus storage

  • std::vec::Vec<T> is a growable array type (in prelude)

  • Example binding:

    #![allow(unused)]
    fn main() {
    let items: Vec<Connection> = Vec::new();
    }
  • std::sync::Arc<std::sync::Mutex<Pool>> guards pooled access in threaded code

  • std::sync::Arc<T> provides atomic reference counting for shared ownership

  • std::sync::Mutex<T> provides mutual exclusion for interior mutability

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::sync::{Arc, Mutex};
    let pool: Arc<Mutex<ConnectionPool>> = Arc::new(Mutex::new(pool));
    }
  • tokio::sync::Semaphore for async pools

  • Example binding:

    #![allow(unused)]
    fn main() {
    use tokio::sync::Semaphore;
    let semaphore: Semaphore = Semaphore::new(10);
    }

Key methods (Vec):

  • Vec::new() creates an empty vector
  • vec.push(item) adds an item to the end
  • vec.pop() removes and returns Option<T> from the end
  • vec.len() returns the number of elements
  • vec.is_empty() returns true if the vector has no elements
  • vec.clear() removes all elements
  • vec.capacity() returns the allocated capacity
  • vec.resize(new_len, value) resizes the vector

Key methods (Arc):

  • Arc::new(data) creates a new Arc with the given data
  • Arc::clone(&arc) creates a new reference to the same data (increments ref count)
  • Arc::strong_count(&arc) returns the number of strong references
  • Arc::try_unwrap(arc) attempts to return the inner data if it's the last reference

Key methods (Mutex):

  • Mutex::new(data) creates a new mutex with the given data
  • mutex.lock() blocks until it acquires the lock, returns MutexGuard<T>
  • mutex.try_lock() tries to acquire the lock without blocking, returns Result<MutexGuard<T>, TryLockError>
  • mutex.get_mut() gets mutable access without taking the lock (only if no other references exist)
  • The MutexGuard<T> automatically releases the lock when dropped

Key methods (Semaphore):

  • Semaphore::new(permits) creates a new semaphore with the given number of permits
  • semaphore.acquire().await waits for a permit to become available (async)
  • semaphore.try_acquire() tries to acquire a permit immediately
  • semaphore.add_permits(n) adds n permits to the semaphore
  • semaphore.available_permits() returns the number of available permits

Cache

Simple English:

A cache is a place where you keep something nearby because you expect to need it again.

Computer science meaning:

A cache is a fast-access storage layer holding recently or frequently needed data to avoid recomputation or slower access.

Why it matters here:

  • in-memory caches trade memory for speed

Rust type references:

  • std::collections::HashMap is the default type for mapping keys to cached values

  • std::collections::HashMap<K, V> shows the type parameters: key type K and value type V

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::collections::HashMap;
    let mut cache: HashMap<String, CachedData> = HashMap::new();
    }
  • std::collections::BTreeMap is an ordered alternative when ordering matters more than average-case lookup speed

  • std::collections::BTreeMap<K, V> shows the type parameters: key type K and value type V

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::collections::BTreeMap;
    let mut ordered_cache: BTreeMap<String, CachedData> = BTreeMap::new();
    }

Key methods:

  • HashMap::new() creates an empty map
  • map.insert(key, value) inserts or updates a key-value pair, returns Option<V> (the old value if the key existed)
  • map.get(&key) returns Option<&V>Some(&value) if present, None otherwise
  • map.get_mut(&mut key) returns Option<&mut V> for mutable access
  • map.remove(&key) removes and returns Option<V>
  • map.contains_key(&key) returns true if the key exists
  • map.entry(key) returns an Entry enum for more complex insertion/update logic
  • map.len() returns the number of entries
  • map.clear() removes all entries
  • map.is_empty() returns true if the map has no entries
  • for (key, value) in &map iterates over key-value pairs

Refined phrasing:

The Rust type system gives us std::collections::HashMap<K, V> for this purpose directly: tracking units by identity and mapping each unit to remembered state or a cached value.

Eviction

Simple English:

Eviction means removing something from a place to make room or enforce a rule.

Computer science meaning:

Eviction is policy-driven removal of items from a cache or in-memory store, usually to control size or freshness.

Why it matters here:

  • bounded caches need a rule for what gets removed

Rust type references:

  • Eviction policies are often implemented with std::collections::HashMap<K, V> plus an ordering structure

  • std::collections::VecDeque<T> maintains access order for LRU eviction

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::collections::{HashMap, VecDeque};
    let mut cache: HashMap<String, CachedData> = HashMap::new();
    let mut access_order: VecDeque<String> = VecDeque::new();
    }
  • Expiration-based eviction often uses std::time::Instant or std::time::SystemTime

  • std::time::Instant represents a monotonic clock for measuring elapsed time

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::time::Instant;
    let expiration_time: Instant = Instant::now() + std::time::Duration::from_secs(300);
    }
  • std::time::SystemTime represents a system clock for wall-clock time

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::time::SystemTime;
    let timestamp: SystemTime = SystemTime::now();
    }

Key

Simple English:

A key is the identifier used to find or group something.

Computer science meaning:

A key is the lookup identity used to retrieve or track state in a map-like structure.

Why it matters here:

  • rate limiters track request state per key
  • caches store values by key
  • metrics may aggregate by key

Rust type references:

  • Keys usually show up as the K in std::collections::HashMap<K, V>

  • Common concrete key types include std::string::String, &str, numeric IDs, or small enums

  • std::string::String is an owned growable string type (in prelude)

  • Example binding:

    #![allow(unused)]
    fn main() {
    let key: String = String::from("user:123");
    }
  • &str is a string slice referencing existing string data (in prelude)

  • Example binding:

    #![allow(unused)]
    fn main() {
    let key: &str = "user:123";
    }

Refined phrasing:

In Rust terms, the key is usually the lookup type in a map such as std::collections::HashMap<K, V>. It is the type-level handle used to find or update the value associated with one unit of the system.

Window

Simple English:

A window is a limited span of time.

Computer science meaning:

A window is a time interval over which events are counted, aggregated, or constrained.

Why it matters here:

  • rate limiters often count requests per window
  • metrics often aggregate over rolling windows

Rust type references:

  • Windows are often represented by std::time::Duration

  • std::time::Duration represents a span of time

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::time::Duration;
    let window: Duration = Duration::from_secs(60);
    }
  • A current window boundary is often tracked using std::time::Instant or std::time::SystemTime

  • std::time::Instant represents a monotonic clock for measuring elapsed time

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::time::Instant;
    let window_start: Instant = Instant::now();
    }
  • Per-window state is commonly stored in std::collections::HashMap<K, V>

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::collections::HashMap;
    let mut window_counts: HashMap<String, u64> = HashMap::new();
    }

Counter

Simple English:

A counter is a number you increase or decrease to track how much has happened.

Computer science meaning:

A counter is a stored numeric state used to count events, operations, or occurrences.

Why it matters here:

  • fixed-window limiters count requests
  • metrics count events

Rust type references:

  • Counters are often stored as primitive unsigned integer types: u32, u64, usize (all in prelude)

  • Example binding:

    #![allow(unused)]
    fn main() {
    let request_count: u64 = 0;
    }
  • For concurrent counters, atomic types are used: std::sync::atomic::AtomicU64, std::sync::atomic::AtomicUsize

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::sync::atomic::{AtomicU64, Ordering};
    let counter: AtomicU64 = AtomicU64::new(0);
    counter.fetch_add(1, Ordering::SeqCst);
    }

Request

Simple English:

A request is an attempt to get some work done by a system.

Computer science meaning:

A request is a unit of incoming work, often an API call, message, or operation to be processed.

Why it matters here:

  • rate limiting is usually applied to incoming requests

Rust type references:

  • Requests are often modeled as custom structs

  • Example binding:

    #![allow(unused)]
    fn main() {
    struct Request { id: String, payload: Vec<u8> }
    let req: Request = Request { id: String::from("req-1"), payload: vec![1, 2, 3] };
    }
  • Request identity may be std::string::String, socket address, user ID, API key, or small enum

  • std::net::SocketAddr represents a socket address

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::net::SocketAddr;
    let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
    }
  • Streams of requests are often delivered through std::sync::mpsc::Receiver<T> or tokio::sync::mpsc::Receiver<T>

  • Example binding:

    #![allow(unused)]
    fn main() {
    use tokio::sync::mpsc::Receiver;
    let mut rx: Receiver<Request> = rx;
    }

Rate

Simple English:

Rate means how often something happens over time.

Computer science meaning:

Rate is the frequency of events per unit time.

Why it matters here:

  • a rate limiter constrains event frequency

Rust type references:

  • Rates are commonly represented as a pair or struct

  • Example: struct Rate { permits: u32, per: std::time::Duration }

  • Example binding:

    #![allow(unused)]
    fn main() {
    let rate: Rate = Rate { permits: 100, per: std::time::Duration::from_secs(60) };
    }
  • Token refill rates may use f64 when fractional refill is modeled (in prelude)

  • Example binding:

    #![allow(unused)]
    fn main() {
    let refill_rate: f64 = 1.5;
    }
  • Elapsed time is typically measured with std::time::Instant and std::time::Duration

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::time::{Instant, Duration};
    let start: Instant = Instant::now();
    let elapsed: Duration = start.elapsed();
    }

Limit

Simple English:

A limit is a boundary you are not supposed to exceed.

Computer science meaning:

A limit is a configured maximum used to reject or delay excess work.

Why it matters here:

  • rate limiters compare counters or tokens against a limit

Rust type references:

  • Limits are usually numeric types: u32, u64, usize (all in prelude)

  • Example binding: let max_requests: u64 = 1000;

  • A reusable limit often appears in a config struct

  • Example: struct RateLimitConfig { max_requests: u64, window: std::time::Duration }

  • Capacity-style limits appear as the bound in channel constructors or buffer sizes

  • Example:

    #![allow(unused)]
    fn main() {
    use std::sync::mpsc::sync_channel;
    let (tx, rx) = sync_channel(100);
    }

Token

Simple English:

A token is a small unit you spend to do something.

Computer science meaning:

In a token bucket, a token is a unit of permission to perform one action.

Why it matters here:

  • token buckets model smoother rate control than fixed windows

Rust type references:

  • Token counts are usually represented by numeric types: u32, u64, or f64 when fractional refill is modeled (all in prelude except f64 which is in prelude)

  • Example binding: let tokens: f64 = 100.0;

  • A token bucket is often modeled as a struct

  • Example: struct TokenBucket { tokens: f64, capacity: f64, last_refill: std::time::Instant, refill_rate: f64 }

  • Example binding: let bucket: TokenBucket = TokenBucket { tokens: 100.0, capacity: 100.0, last_refill: std::time::Instant::now(), refill_rate: 10.0 };

Event

Simple English:

An event is something that happened.

Computer science meaning:

An event is a message or occurrence that may be observed, processed, or forwarded by the system.

Why it matters here:

  • event buses route events from producers to subscribers

Rust type references:

  • Events are often modeled as enums when there are multiple event variants

  • Example: enum Event { UserLoggedIn(UserId), DataReceived(Vec<u8>), ConnectionClosed }

  • Example binding:

    #![allow(unused)]
    fn main() {
    let event: Event = Event::UserLoggedIn(UserId(123));
    }
  • Channels carry values of some event type T

  • Example:

    #![allow(unused)]
    fn main() {
    use tokio::sync::mpsc::Sender;
    let tx: Sender<Event> = tx;
    }
  • Event payloads may also be plain structs when there is only one event shape

  • Example: struct Event { id: String, timestamp: std::time::Instant, payload: Vec<u8> }

Publish

Simple English:

To publish is to send something outward so others can receive it.

Computer science meaning:

Publishing means submitting an event or message to a bus, topic, or channel for downstream consumers.

Rust type references:

  • Publishing often appears as std::sync::mpsc::Sender<T>::send in threaded code

  • Example:

    #![allow(unused)]
    fn main() {
    use std::sync::mpsc::Sender;
    tx.send(Event::UserLoggedIn(123)).unwrap();
    }
  • In async systems it often appears as tokio::sync::mpsc::Sender<T>::send().await

  • Example:

    #![allow(unused)]
    fn main() {
    use tokio::sync::mpsc::Sender;
    tx.send(Event::UserLoggedIn(123)).await.unwrap();
    }

Subscribe

Simple English:

To subscribe is to register interest in receiving something.

Computer science meaning:

A subscriber registers to receive future events from a source or topic.

Rust type references:

  • Subscription often returns a receive-side type: std::sync::mpsc::Receiver<T> or tokio::sync::mpsc::Receiver<T>
  • Example:
    #![allow(unused)]
    fn main() {
    use std::sync::mpsc::Receiver;
    let rx: Receiver<Event> = rx;
    }

Broadcast

Simple English:

Broadcast means send the same thing to many recipients.

Computer science meaning:

Broadcast is fan-out delivery of one message to multiple consumers.

Rust type references:

  • tokio::sync::broadcast::channel creates a broadcast channel for async fan-out

  • tokio::sync::broadcast::Sender<T> and tokio::sync::broadcast::Receiver<T> show the message type parameter

  • Example binding:

    #![allow(unused)]
    fn main() {
    use tokio::sync::broadcast::{channel, Sender, Receiver};
    let (tx, _rx1): (Sender<Event>, Receiver<Event>) = channel(100);
    }
  • Fan-out can also be modeled manually as std::vec::Vec<Sender<T>>

  • Example:

    #![allow(unused)]
    fn main() {
    use std::vec::Vec;
    let mut senders: Vec<std::sync::mpsc::Sender<Event>> = Vec::new();
    }

Producer and Consumer

Simple English:

A producer creates work or messages. A consumer receives or processes them.

Computer science meaning:

Producer-consumer is a concurrency model where one side emits work and another side processes it, often with a queue or channel in between.

Rust type references:

  • Producers usually own std::sync::mpsc::Sender<T> or tokio::sync::mpsc::Sender<T> handles

  • Example:

    #![allow(unused)]
    fn main() {
    use std::sync::mpsc::Sender;
    let tx: Sender<Job> = tx;
    }
  • Consumers usually own std::sync::mpsc::Receiver<T> or tokio::sync::mpsc::Receiver<T> handles

  • Example:

    #![allow(unused)]
    fn main() {
    use std::sync::mpsc::Receiver;
    let rx: Receiver<Job> = rx;
    }
  • Shared queues may use std::sync::Arc<std::sync::Mutex<std::collections::VecDeque<T>>>

  • Example:

    #![allow(unused)]
    fn main() {
    use std::sync::{Arc, Mutex};
    use std::collections::VecDeque;
    let queue: Arc<Mutex<VecDeque<Job>>> = Arc::new(Mutex::new(VecDeque::new()));
    }

Retry

Simple English:

Retry means try again after a failure.

Computer science meaning:

A retry is a repeated attempt to perform an operation after it failed.

Rust type references:

  • Retry state is often modeled with counters: u32 attempt counts (in prelude)

  • Example binding: let attempts: u32 = 0;

  • Retryable work is often stored as structs containing payload plus attempt metadata

  • Example: struct RetryableJob<T> { payload: T, attempts: u32, max_attempts: u32 }

  • Retry results are usually modeled with std::result::Result<T, E>

  • std::result::Result<T, E> has variants: std::result::Ok(T) and std::result::Err(E) (in prelude)

  • Example binding: let result: Result<Job, Error> = Ok(job);

Key methods (Result):

  • Result::Ok(value) creates a success variant
  • Result::Err(error) creates an error variant
  • result.is_ok() returns true if the result is Ok
  • result.is_err() returns true if the result is Err
  • result.ok() converts to Option<T>, returning Some(value) for Ok and None for Err
  • result.err() converts to Option<E>, returning None for Ok and Some(error) for Err
  • result.unwrap_or(default) returns the value if Ok, or the default if Err
  • result.unwrap_or_else(default_fn) returns the value if Ok, or calls the function if Err
  • result.map(f) applies function f if Ok, passes through Err unchanged
  • result.map_err(f) applies function f if Err, passes through Ok unchanged
  • result.and_then(f) chains operations, only calls f if Ok
  • result.or_else(f) chains error handling, only calls f if Err

Backoff

Simple English:

Backoff means waiting longer before trying again.

Computer science meaning:

Backoff is a retry policy that increases delay between attempts, often exponentially.

Rust type references:

  • Backoff delays are represented by std::time::Duration

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::time::Duration;
    let delay: Duration = Duration::from_millis(100);
    }
  • Next-attempt timing is usually tracked with std::time::Instant

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::time::Instant;
    let next_attempt: Instant = Instant::now() + delay;
    }
  • A backoff policy is often encoded as a function or struct returning the next std::time::Duration

  • Example: fn backoff(attempt: u32) -> std::time::Duration { std::time::Duration::from_millis(100 * 2_u64.pow(attempt)) }

Schedule

Simple English:

To schedule is to decide when something should happen.

Computer science meaning:

Scheduling assigns work to a future execution time or execution resource.

Rust type references:

  • Schedules often use std::time::Instant, std::time::Duration, or std::time::SystemTime

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::time::{Instant, Duration};
    let when: Instant = Instant::now() + Duration::from_secs(5);
    }
  • Scheduled work may be stored as tuples: (std::time::Instant, Job)

  • Example: struct ScheduledJob<T> { when: std::time::Instant, job: T }

  • For priority scheduling, std::collections::BinaryHeap<T> can be used

  • std::collections::BinaryHeap<T> is a priority queue (max-heap by default)

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::collections::BinaryHeap;
    let mut heap: BinaryHeap<ScheduledJob> = BinaryHeap::new();
    }
  • Async schedulers often combine timers with tokio::time

  • Example:

    #![allow(unused)]
    fn main() {
    use tokio::time::{sleep, Duration};
    sleep(Duration::from_secs(5)).await;
    }

Metric

Simple English:

A metric is a measurement.

Computer science meaning:

A metric is a collected numerical observation about system behavior.

Rust type references:

  • Counters are often u64 (in prelude)

  • Example binding:

    #![allow(unused)]
    fn main() {
    let request_count: u64 = 0;
    }
  • Latency and durations use std::time::Duration

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::time::Duration;
    let latency: Duration = Duration::from_millis(50);
    }
  • Metrics are commonly stored in std::collections::HashMap<String, u64> or custom structs

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::collections::HashMap;
    let mut metrics: HashMap<String, u64> = HashMap::new();
    }
  • For histogram buckets, arrays or std::vec::Vec<u64> are used

  • Example binding:

    #![allow(unused)]
    fn main() {
    let mut histogram: [u64; 10] = [0; 10];
    }

Bucket

Simple English:

A bucket is a container used to group things.

Computer science meaning:

A bucket is a grouping unit, often for time-based aggregation or capacity-based modeling.

Rust type references:

  • Buckets are often represented as std::vec::Vec<u64>, arrays, or std::collections::HashMap<K, u64>

  • std::vec::Vec<T> is a growable array type (in prelude)

  • Example binding:

    #![allow(unused)]
    fn main() {
    let mut buckets: Vec<u64> = vec![0; 10];
    }
  • Token buckets are commonly structs that hold token count and refill metadata

  • Example: struct TokenBucket { tokens: f64, capacity: f64, last_refill: std::time::Instant, refill_rate: f64 }

  • Example binding:

    #![allow(unused)]
    fn main() {
    let bucket: TokenBucket = TokenBucket { tokens: 100.0, capacity: 100.0, last_refill: std::time::Instant::now(), refill_rate: 10.0 };
    }

Aggregate

Simple English:

To aggregate is to combine many smaller things into a summary.

Computer science meaning:

Aggregation combines multiple events or values into summary statistics like counts or averages.

Rust type references:

  • Aggregates are often stored in structs

  • Example: struct Stats { count: u64, sum: u64, max: u64, min: u64 }

  • Example binding:

    #![allow(unused)]
    fn main() {
    let stats: Stats = Stats { count: 100, sum: 5000, max: 100, min: 10 };
    }
  • Keyed aggregates are often stored in std::collections::HashMap<K, Aggregate>

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::collections::HashMap;
    let mut by_user: HashMap<String, Stats> = HashMap::new();
    }

Connection

Simple English:

A connection is an active link to another system.

Computer science meaning:

A connection is a reusable communication resource such as a database or network session.

Rust type references:

  • The concrete type depends on the client library

  • std::net::TcpStream is a TCP stream connection

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::net::TcpStream;
    let stream: TcpStream = TcpStream::connect("127.0.0.1:8080")?;
    }
  • Database libraries provide their own connection types

  • Example:

    #![allow(unused)]
    fn main() {
    use sqlx::PgConnection;
    let conn: PgConnection = PgConnection::connect("postgresql://...")?;
    }
  • Pools usually store connections in std::vec::Vec<T>, std::collections::VecDeque<T>, or custom pool structs

  • Example: struct ConnectionPool { connections: VecDeque<Connection>, max_size: usize }

Acquire and Release

Simple English:

Acquire means take one for use. Release means return it.

Computer science meaning:

Acquire/release are resource-pool operations for borrowing and returning reusable resources.

Rust type references:

  • Acquisition often returns std::option::Option<T>, std::result::Result<T, E>, or a guard type

  • std::option::Option<T> has variants: std::option::Some(T) or std::option::None (in prelude)

  • Example binding: let maybe_conn: Option<Connection> = pool.acquire().ok();

  • std::result::Result<T, E> has variants: std::result::Ok(T) or std::result::Err(E) (in prelude)

  • Example binding: let conn: Result<Connection, Error> = pool.acquire();

  • Release may be explicit or handled through the std::ops::Drop trait

  • std::ops::Drop is a trait for custom cleanup logic

  • Example: impl Drop for ConnectionGuard { fn drop(&mut self) { /* return to pool */ } }

Key methods (Option):

  • Option::Some(value) creates a present variant
  • Option::None represents the absence of a value
  • option.is_some() returns true if the option is Some
  • option.is_none() returns true if the option is None
  • option.unwrap() returns the value if Some, panics if None
  • option.unwrap_or(default) returns the value if Some, or the default if None
  • option.unwrap_or_else(default_fn) returns the value if Some, or calls the function if None
  • option.map(f) applies function f if Some, returns None if None
  • option.and_then(f) chains operations, only calls f if Some
  • option.or(default) returns self if Some, or default if None
  • option.ok_or(error) converts Option<T> to Result<T, E>, turning None into Err(error)

Capacity

Simple English:

Capacity is how much can be held or supported.

Computer science meaning:

Capacity is the configured maximum size of a queue, pool, or cache.

Rust type references:

  • Capacities are usually usize (in prelude)

  • Example binding:

    #![allow(unused)]
    fn main() {
    let capacity: usize = 100;
    }
  • Capacity constructors appear in std::vec::Vec::with_capacity, std::collections::HashMap::with_capacity

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::collections::HashMap;
    let map: HashMap<String, Value> = HashMap::with_capacity(100);
    }
  • Semaphore permits are another capacity-like control type

  • Example:

    #![allow(unused)]
    fn main() {
    use tokio::sync::Semaphore;
    let semaphore: Semaphore = Semaphore::new(10);
    }

Timeout

Simple English:

A timeout is a limit on how long you are willing to wait.

Computer science meaning:

A timeout is a failure boundary triggered when an operation takes too long.

Rust type references:

  • Timeouts are represented by std::time::Duration

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::time::Duration;
    let timeout: Duration = Duration::from_secs(30);
    }
  • Deadline tracking often uses std::time::Instant

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::time::Instant;
    let deadline: Instant = Instant::now() + timeout;
    }
  • Tokio async timeouts are commonly expressed with tokio::time::timeout

  • Example: use tokio::time::{timeout, Duration}; match timeout(Duration::from_secs(5), operation).await { Ok(result) => result, Err(_) => /* timeout */ }

Recent / LRU

Simple English:

Recent means used not long ago.

Computer science meaning:

LRU means least recently used, an eviction policy that removes the item whose last access is oldest.

Rust type references:

  • An LRU cache is often built from std::collections::HashMap<K, V> plus an ordering structure

  • std::collections::VecDeque<K> or a linked list maintains access order

  • Example: struct LruCache<K, V> { data: HashMap<K, V>, access_order: VecDeque<K>, capacity: usize }

  • Access recency may be tracked with timestamps such as std::time::Instant

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::time::Instant;
    let last_access: Instant = Instant::now();
    }
  • Production code may use a dedicated lru::LruCache<K, V> type from a crate

Buffer

Simple English:

A buffer is a temporary holding area.

Computer science meaning:

A buffer is temporary storage used before processing, sending, or flushing data.

Rust type references:

  • Buffers are often std::vec::Vec<T>, std::string::String, bytes::Bytes, or std::collections::VecDeque<T>

  • std::vec::Vec<T> is a growable byte buffer (in prelude)

  • Example binding:

    #![allow(unused)]
    fn main() {
    let mut buffer: Vec<u8> = Vec::new();
    }
  • std::string::String is a growable text buffer (in prelude)

  • Example binding:

    #![allow(unused)]
    fn main() {
    let mut buffer: String = String::new();
    }
  • bytes::Bytes is a reference-counted byte buffer from the bytes crate

  • Example:

    #![allow(unused)]
    fn main() {
    use bytes::Bytes;
    let mut buffer: Bytes = Bytes::new();
    }
  • std::collections::VecDeque<T> for queue-like behavior

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::collections::VecDeque;
    let mut buffer: VecDeque<u8> = VecDeque::new();
    }

Backpressure

Simple English:

Backpressure means the system is pushing back because work is arriving faster than it can be handled.

Computer science meaning:

Backpressure is a control effect where a full queue, slow consumer, bounded buffer, or saturated downstream component forces producers to slow down, block, drop work, or fail.

OR

Backpressure is a control mechanism that propagates downstream capacity limits back to producers, so the system stays stable instead of accepting work it cannot process.

Why I used the word “effect”: The important thing is not the data structure itself, but the system-level consequence. A bounded channel is just a type. Backpressure is the effect it creates on producer behavior.

In a Tokio system, this often shows up when a bounded tokio::sync::mpsc::channel is full and send().await makes the producer wait instead of letting work grow without bound.

Why it matters here:

  • bounded queues create backpressure
  • worker pools can signal overload through backpressure
  • channels can apply backpressure when receivers cannot keep up
  • batching systems often need backpressure to stop unbounded growth

Rust type references:

  • std::sync::mpsc::sync_channel introduces bounded capacity and therefore backpressure

  • Example:

    #![allow(unused)]
    fn main() {
    use std::sync::mpsc::{sync_channel, SyncSender};
    let (tx, rx): (SyncSender<Job>, Receiver<Job>) = sync_channel(100);
    }
  • tokio::sync::mpsc::channel with a bounded channel introduces async backpressure

  • Example:

    #![allow(unused)]
    fn main() {
    use tokio::sync::mpsc::{channel, Sender};
    let (tx, mut rx): (Sender<Job>, Receiver<Job>) = channel(100);
    }
  • Bounded queues implemented with std::collections::VecDeque<T> plus capacity checks create explicit backpressure

  • Example: if queue.len() >= capacity { return Err(Error::Full); }

Refined phrasing:

Backpressure is the system's way of making overload visible instead of letting memory or latency grow without bound. In Rust terms, bounded channels and bounded queues are common typed mechanisms for expressing it.

Batch

Simple English:

A batch is a group handled together.

Computer science meaning:

A batch is a group of items processed or flushed as one unit for efficiency.

Rust type references:

  • Batches are often std::vec::Vec<T> (in prelude)

  • Example binding:

    #![allow(unused)]
    fn main() {
    let batch: Vec<Job> = vec![/* items */];
    }
  • Queue-like batching may use std::collections::VecDeque<T>

  • Example binding:

    #![allow(unused)]
    fn main() {
    use std::collections::VecDeque;
    let mut batch: VecDeque<Job> = VecDeque::new();
    }
  • Keyed batches may use std::collections::HashMap<K, std::vec::Vec<T>>

  • Example:

    #![allow(unused)]
    fn main() {
    use std::collections::HashMap;
    let mut by_user: HashMap<String, Vec<Job>> = HashMap::new();
    }

Refined phrasing:

In Rust, a batch is usually just an explicit collection type chosen to match the access pattern. Most of the time that means std::vec::Vec<T>, and sometimes std::collections::VecDeque<T> when front-removal matters.

Flush

Simple English:

To flush is to push out what has been held temporarily.

Computer science meaning:

Flush means forcing buffered or batched data to be emitted, written, or processed now.

Rust type references:

  • Flushing often drains a std::vec::Vec<T> or std::collections::VecDeque<T>

  • Example: let batch: Vec<Job> = std::mem::take(&mut buffer);

  • I/O flushing uses std::io::Write::flush

  • std::io::Write is a trait for writing bytes (in prelude)

  • Example: use std::io::Write; writer.flush()?;

  • Async buffering often combines std::vec::Vec<T> with tokio::time::interval or timeout logic

  • Example:

    #![allow(unused)]
    fn main() {
    use tokio::time::{interval, Duration};
    let mut ticker = interval(Duration::from_secs(1));
    ticker.tick().await; /* flush */
    }

Computer science meaning:

Flushing means forcing buffered data to be written, emitted, or processed.

Throughput and Latency

Simple English:

Throughput is how much work gets done. Latency is how long one piece of work takes.

Computer science meaning:

Throughput is work completed per unit time. Latency is end-to-end delay for a single operation.

Why This Matters

If the words become clear, the design becomes easier.

You stop seeing:

  • ten unrelated interview problems

and start seeing:

  • lines of work
  • stored state by identity
  • reusable resources
  • time-bounded behavior
  • grouped processing

That is the right level of abstraction before code.