When we wrote our Fibonacci server in the previous chapter, we had to do all the message handling ourselves. It wasn’t difficult, but it was tedious. Our scheduler also had to keep track of three pieces of state information:

  • The queue of numbers to process
  • The results generated so far
  • The list of active PIDs

Most servers have a similar set of needs, so OTP provides libraries that do all the low-level work for us.

When we write an OTP server, we write a module containing one or more callback functions with standard names. OTP will invoke the appropriate callback to handle a particular situation. For example, when someone sends a request to our server, OTP calls our handle_call function, passing in the request, the caller, and the current server state. Our function responds by returning a tuple containing an action to take, the return value for the request, and an updated state.

State and the single server

Think back to our recursive Fibonacci code. Where did it keep all the intermediate results as it worked? It passed them to itself, recursively, as parameters. In fact, all three of its parameters were used for state information.

Now, think about servers. They use recursion to loop, handling one request on each call. So, they can also pass the state to themselves as a parameter in this recursive call. And that’s one of the things OTP manages for us. Our handler functions get passed the current state (as their last parameter), and they return, among other things, a potentially updated state. Every state a function returns gets passed to the next request handler.

Our first OTP server

Let’s write the simplest OTP server. We pass it a number when we start it up, and that becomes the current state of the server. When we call it with a :next_number request, it returns that current state to the caller. At the same time, it increments the state, ready for the next call. Basically, each time we call it, we get an updated sequence number.

Create a new project using mix

Let’s start by creating a new mix project in our work directory. We’ll call it sequence.

$ mix new sequence

Create the basic sequence server

Now we’ll create Sequence.Server, our server module. We move into the sequence directory and create a subdirectory under lib/ that’s also called sequence.

$ cd sequence
$ mkdir lib/sequence

Next, we add the file server.ex to lib/sequence/:

Get hands-on with 1200+ tech skills courses.