whoami
Lucas Jenß
cat /etc/motd
The Coding Journal ツ — Notes taken on an epic coding journey. Technical solutions, debugging notes, and practical guides from the trenches of software development.
ls -la ~/languages/
- drwxr-xr-x
- ▶ PHP
- ▶ Ruby
- ▶ Scala
- ▶ C#
- ▶ JavaScript
- ▶ Objective-C
- ▶ Shell Scripting
ls -la ~/toolchain/
- drwxr-xr-x
- ▶ Typo3
- ▶ Akka
- ▶ Capistrano
- ▶ Git
- ▶ MAMP
- ▶ Adobe Illustrator
- ▶ NSTrackingArea (Cocoa)
uname -a
- drwxr-xr-x
- ▶ Mac OS X
- ▶ Unix
Practical Backpressure Patterns For Akka Streams
Streaming systems rarely fail because a single record is difficult to process. They fail when records arrive faster than a downstream service, database, file writer or network connection can handle them. A queue grows, memory disappears, latency climbs and an apparently healthy application begins timing out.
Akka Streams provides a disciplined way to manage that mismatch. Its demand signalling lets a consumer communicate how much data it can accept, while stages such as buffers, throttles and asynchronous boundaries help shape the flow. Understanding those mechanisms makes it easier to build reliable pipelines for Australian services, from Sydney-based APIs to Melbourne data processing jobs.
Why Demand Matters In Stream Systems
A pipeline has a production rate and a consumption rate. If a source emits 20,000 events per second while a database can commit only 5,000, the excess must either wait, be discarded or cause the producer to slow down. Backpressure is the mechanism that chooses controlled waiting and slowing rather than allowing unbounded growth.
Akka backpressure is based on Reactive Streams principles. A downstream stage requests elements from upstream, and upstream should not send more than has been requested. This demand travels through operators such as map, filter, grouped and mapAsync, creating a flow-controlled chain instead of a set of independent loops.
This model is especially useful when a pipeline combines unlike systems. An NBN connection, a local Sydney service and a third-party payment API may each have different throughput and latency characteristics. Treating them as equally fast is an invitation to overload the slowest component.
How Akka Propagates Demand
In Akka Streams, a Source produces elements, a Flow transforms them and a Sink consumes them. A simple pipeline can be expressed as source.via(flow).to(sink), but the important behaviour is underneath: the sink asks for demand, each stage passes that demand upstream, and the source emits only when capacity exists.
Asynchronous operations need particular care. mapAsync(4) allows four futures to run concurrently, which can improve throughput without removing flow control. The number is a concurrency limit, not a promise that four operations will always be active. If the downstream stage slows, demand eventually reduces and upstream production follows.
An asynchronous boundary changes where work and messages are scheduled, but it does not automatically create infinite capacity. A boundary can be valuable when CPU-heavy parsing should not block I/O, yet it should be paired with a deliberate buffer policy. For developers moving between ecosystems, notes in the Scala development archive can provide useful background when comparing functional concurrency patterns.
Designing Buffers And Overflow Policies
Buffers absorb short bursts. They are not a cure for a permanent rate mismatch. A buffer of 1,000 records may smooth a brief network pause, but if the consumer remains slower than the producer, those records will eventually fill it. Once full, the chosen overflow behaviour becomes part of the application’s data contract.
buffer can be configured with strategies such as backpressure, dropping the oldest element, dropping the newest element or failing the stream. Backpressuring is appropriate for invoices or audit events where every item matters. Dropping may be acceptable for live sensor readings, where a current measurement is more useful than a stale one.
A lossy policy needs to be visible and measurable. Count discarded elements, expose queue depth and record the reason for a stream failure. A Melbourne traffic dashboard can reasonably discard outdated position updates; a payroll export cannot. The distinction belongs in domain design, not just in a performance configuration file.
Building A Controlled Streaming Pipeline
A robust pipeline starts by identifying the slowest meaningful operation. If records are read from Kafka, transformed, enriched through HTTP and written to PostgreSQL, measure each stage separately. Use bounded mapAsync concurrency for remote calls, and avoid turning every step into an unconstrained future pool.
Throttling is useful when a service has a published rate limit or a predictable capacity ceiling. It can protect an external API from bursts, although it should not replace proper backpressure. Retries also need limits: a failed request that is retried indefinitely can multiply traffic and keep a queue permanently busy.
A practical Akka Streams shape might read a bounded batch, apply mapAsync(8) to enrich records, group successful results into database batches and commit them through a sink. Failed records can be sent to a dead-letter path with their original identifier. For deployment notes involving configuration, process supervision and repeatable releases, the deployment troubleshooting notes are a useful companion to stream design.
Operational Checks For Production Streams
Backpressure is effective only when the surrounding application respects it. Avoid converting a stream into a collection with runFold when the collection can grow with input size. Be cautious with Sink.queue, since a queue can move the pressure point into application code and make memory usage harder to see.
Monitoring should cover throughput, processing latency, in-flight asynchronous operations, buffer occupancy, rejected messages and materialised stream failures. Australian teams may deploy in Sydney or Melbourne cloud regions while serving users across several time zones, so dashboards should show both UTC and the operational timezone used by the team.
Useful checks before releasing a pipeline include:
- Set explicit buffer sizes and document why each one exists.
- Limit
mapAsyncconcurrency according to downstream capacity. - Track dropped, delayed, retried and dead-lettered records separately.
- Test shutdown so in-flight work is drained or safely replayed.
- Review sensitive payloads under the Australian Privacy Act before logging them.
Privacy deserves special attention in event systems. A stream carrying customer identifiers, location data or health information may be copied into logs, retry queues and monitoring tools. Data minimisation, access controls and retention rules should apply to those secondary paths as carefully as they apply to the primary database.
Comparing Common Flow-Control Choices
The right strategy depends on whether data can be delayed, discarded or replayed. A financial transaction normally requires bounded waiting and durable recovery. A live sports score or public transport position may prioritise freshness, making controlled loss preferable to displaying old information.
The following comparison helps separate mechanisms that are sometimes treated as interchangeable. A throttle regulates rate, a buffer absorbs temporary variation and backpressure connects downstream capacity to upstream demand. In a real pipeline, they can be combined, but each solves a different problem.
| Mechanism | Best Use | Main Risk | Practical Akka Choice |
|---|---|---|---|
| Propagated backpressure | Lossless processing with a variable consumer rate | Upstream latency increases | Default stream behaviour |
| Bounded buffer | Short bursts or brief downstream pauses | Capacity is eventually exhausted | buffer with a deliberate strategy |
| Throttle | External rate limits and predictable quotas | It may reduce throughput unnecessarily | throttle around the constrained call |
mapAsync limit |
Concurrent I/O with bounded in-flight work | Too much concurrency overloads a dependency | Start small and measure |
| Dropping strategy | Freshness-sensitive telemetry and dashboards | Silent data loss | Drop only with metrics and clear semantics |
| Durable queue or broker | Restart recovery and decoupled services | Operational complexity and duplicate delivery | Use when replay matters |
For a PHP service that hands work to an Akka application, the boundary should communicate capacity clearly rather than accepting unlimited HTTP requests. A bounded ingress queue, a 429 response or a durable broker can be better than allowing web workers to accumulate blocked requests; related PHP troubleshooting notes can help when diagnosing the service side of that boundary.
A pipeline should also define what happens during shutdown. Stop accepting new work, allow safe in-flight operations to finish, persist or redirect anything that cannot finish, and make retries idempotent. These decisions matter more than a small benchmark improvement because they determine whether a restart creates loss, duplication or a clean recovery.
Start with the default demand-driven behaviour, then add only the capacity controls the workload requires. Run a load test with a deliberately slow sink, observe queue depth and latency, and verify that memory stays bounded. Apply the same exercise to failure and restart scenarios so the pipeline remains predictable when production traffic, Australian service windows and external dependencies put it under pressure.
cat ~/interests.json
| Key | Value |
|---|---|
| editor | Terminal-first workflow |
| os | Mac OS X / Unix |
| vcs | Git, distributed version control |
| deploy | Capistrano, cron automation |
| graphics | SVG, Adobe Illustrator troubleshooting |
| networking | IP validation, SSH, VPN |
git log --oneline --reverse
Solving SVG import issues in Adobe Illustrator CS6 and CC
When importing an SVG into Illustrator, the operation fails with an unknown error [CANT]. A workaround for this Adobe-side bug.
Solving NDK build issues on OS X
Troubleshooting native development kit compilation problems on Mac OS X.
Programmatically adding PHP generated TypoScript to the backend configuration
Integrating dynamically generated TypoScript into Typo3 backend setups using PHP.
ArgumentError: Could not parse PKey: no start line
Debugging an SSH key parsing error encountered during deployment.
Validating IP-Addresses in PHP
Using PHP filter functions with flags like FILTER_FLAG_IPV4 and FILTER_FLAG_IPV6, and understanding how filter_var handles reserved IP addresses.
Cocoa: Using NSTrackingArea
A short tutorial on using Cocoa's NSTrackingArea to capture mouseEntered and mouseExited events.
cat ~/contact.txt