Scala
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Scala
-
Section 4: Functional Scala
-
Section 5: Collections in Depth
-
Section 6: Type System
-
Section 7: Concurrency and Ecosystem
-
Section 8: Practical Projects
-
Section 9: Interview Practice
-
Section 10: Data Structures and Algorithms in Scala
-
Section 11: More Practice Exercises
-
Section 12: Advanced Functional Patterns
-
Section 13: More Ecosystem
-
Section 14: Scala Collections Library Deep Dive
-
Section 15: Scala Standard Library Deep Dive
-
Section 16: Akka Ecosystem Deep Dive
-
Section 17: Cats and Cats Effect Deep Dive
-
Section 18: Play Framework Deep Dive
-
Section 19: Apache Spark with Scala Deep Dive
-
Section 20: Scala Build Tools Deep Dive
-
Section 21: Scala 3 Specific Features
-
90: Union and Intersection Types
-
Section 22: Scala Testing Deep Dive
-
Section 23: Functional Domain Modeling
-
Section 24: More Data Structures and Algorithms in Scala
-
Section 25: Scala for Data Engineering
-
Section 26: More Practical Projects
-
Section 27: More Interview and Review
-
Section 28: ZIO Ecosystem Deep Dive
-
Section 29: Scala for Machine Learning
-
Section 30: Scala Microservices Architecture
-
Section 31: Scala Type System Deep Dive
-
Section 32: More Practice and Drills
-
Section 33: Scala Performance Deep Dive
-
Section 34: Scala Ecosystem Tooling
-
Section 35: Scala for Reactive Systems
-
Section 36: More Real-World Case Studies
-
Section 37: Scala for Financial Systems
-
Section 38: Scala GraphQL and gRPC
-
Section 39: More Final Projects
-
Section 40: More Interview and Final Review
-
Section 41: Scala for Streaming Data
-
Section 42: Scala Security Practices
-
Section 43: More Language Deep Dive
-
Section 44: Scala Command-Line Tools
-
Section 45: Scala Documentation and Style
-
Section 46: Scala Dependency Management
-
Section 47: More Practical Backend Patterns
-
Section 48: Scala for Event-Driven Architecture
-
Section 49: More Practice Drills Round 2
-
Section 50: Scala Compiler Deep Dive
-
Section 51: Scala for Web Frontends
-
Section 52: More Data Engineering Practice
-
Section 53: Scala Observability
-
Section 54: More Advanced Practice Projects
-
Section 55: Scala for Legacy Java Integration
-
Section 56: More Testing Practice
-
Section 57: Final Mastery Review
-
Section 58: Scala History and Ecosystem Context
-
Section 59: More Concurrency Patterns
-
Section 60: Scala for Configuration Management
-
Section 61: More Domain Modeling Practice
160: Building a Real-Time Analytics Dashboard Backend
How do I handle a massive stream of events without crashing my server?
If you're building an analytics dashboard for something like an e-commerce site during a Black Friday sale, you can't just throw every incoming event into a List and hope for the best. You'll run out of heap space in minutes. This is where backpressure comes in. I always recommend using Pekko Streams (or Akka) for this because it handles the "producer is faster than the consumer" problem natively.
Instead of a traditional imperative loop, you define a pipeline. In our case, we're processing PurchaseEvent objects. By using a Source and a Flow, the system ensures that if your aggregation logic slows down, the source (like a Kafka topic) is told to slow down too.
case class PurchaseEvent(orderId: String, amount: Double, category: String, timestamp: Long)
// A simple stream that filters out "test" orders and maps them to a simplified metric
val analyticsFlow = Flow[PurchaseEvent]
.filter(_.amount > 0) // Ignore zero-dollar test transactions
.map(event => (event.category, event.amount))
.groupedWithin(100, 1.second) // Batch them to avoid overwhelming the downstream
The groupedWithin call is a lifesaver. It prevents your backend from trying to push a WebSocket update for every single single-cent transaction, instead bundling them into manageable chunks every second.
How do I aggregate data over a sliding window instead of just counting everything since startup?
A dashboard that shows "Total Sales Since 2022" is a report; a dashboard that shows "Sales in the last 5 minutes" is real-time analytics. To do this in Scala, you need a way to maintain state that expires. While you could use a database, for a high-frequency dashboard, I prefer doing this in-memory using a stateful map or a sliding window logic.
I usually implement a StatefulMap approach where I keep a buffer of timestamps. Here is a simplified version of how you might track the rolling sum of revenue:
class RevenueAggregator {
private var window = scala.collection.mutable.Queue[(Long, Double)]()
def addAndCalculate(amount: Double, now: Long): Double = {
window.enqueue((now, amount))
// Slide the window: remove any events older than 5 minutes
val fiveMinutesAgo = now - (5 * 60 * 1000)
while (window.nonEmpty && window.head._1 < fiveMinutesAgo) {
window.dequeue()
}
window.map(_._2).sum
}
}
It's a simple queue, but it's effective. Just remember: if you're running this across a cluster, you'll need to move this state into something like Redis or use a distributed streaming engine. For a single-node backend, this is plenty fast.
How do I push these updates to multiple users in real-time without polling?
You don't want your frontend hitting an endpoint every 500ms—that's just an expensive way to waste CPU cycles. You want a "push" model. In the Scala ecosystem, the BroadcastHub is your best friend here. It allows you to take a single stream of analytics and "fan it out" to every connected WebSocket client.
Think of it like a radio station: the backend broadcasts the current metrics, and the users just tune in. Here is how you hook that up to a WebSocket route:
// Create a hub that broadcasts the aggregated metrics to all subscribers
val (hub, source) = BroadcastHub.sinkAndSource[DashboardMetrics](bufferSize = 256)
// The stream pipeline feeds into the hub
analyticsFlow
.map(batch => calculateMetrics(batch))
.to(hub)
.run()
// In your HTTP routes:
val route = path("ws" / "metrics") {
get {
complete {
HttpEntity.WebSocket { request, session =>
// Each user gets their own stream from the hub
val flow = Flow[String].ignore // We only push, not receive
source.map(metrics => metrics.toJson.toString).to(session)
}
}
}
}
The magic here is that source is a "hot" stream. New users joining the dashboard don't get the entire history of the app; they just start receiving the latest updates as they happen.
📋 Practical Task
Implementing a High-Value Order Filter Stream
Your analytics dashboard is getting too noisy. The stakeholders only want a specific "High-Value Alert" feed that pushes orders greater than $500 to a separate WebSocket channel.
Your Task:
- Create a new
Flow[PurchaseEvent]that filters for orders whereamount > 500.0. - Implement a transformation that converts the
PurchaseEventinto aHighValueAlertcase class (which should contain theorderIdand a formatted string:"Large purchase of $[amount] detected!"). - Connect this flow to a second
BroadcastHubso that these alerts are broadcast independently from the general metrics stream. - Ensure the stream is non-blocking and can handle at least 1,000 events per second without dropping alerts.
There are no comments for now.