Unique ID Generation#
Info
This example is for Challenge #2: Unique ID Generation
In this challenge we generate globally-unique IDs in a distributed network
Imports
import com.bilalfazlani.zioMaelstrom.*
import zio.json.*
import zio.*
Here, we define the protocol of the node. It includes messages which the node can handle and messages it can send
Message definitions
case class Generate() derives JsonDecoder
case class GenerateOk(id: String) derives JsonEncoder
Unlike echo, this node has some state which we have modeled using Ref[Int]. We increment the Int every time we generate a new Id. To make it unique across the cluster, we append the node Id to the generated id.
Why use a Ref?
Using a Ref ensures that I can update the state in a thread-safe manner. This is important because the messages are received and processed concurrently
Node application
object Main extends MaelstromNode {
val program = receive[Generate] { _ =>
for {
generated <- ZIO.serviceWithZIO[Ref[Int]](_.getAndIncrement)
me <- MaelstromRuntime.me // (1)!
combinedId = s"${me}_${generated}"
_ <- reply(GenerateOk(id = combinedId)) // (2)!
} yield ()
}.provideSome[MaelstromRuntime](ZLayer(Ref.make(0)))
}
MaelstromRuntime.mereturns theNodeIdof self node.replysends a reply to the sender of the message. The correlation between the request and reply is automatically handled by the framework using themessageId
Tip
ZLayeris used to inject the state.provideSomeis used to provideRef[Int]layer to the program. This method provides all the layers exceptMaelstromRuntime
Note
Source code for this example can be found on Github