E4 — OTP: Our Terrier Puppies
Due Tuesday, 16 April 2024, 11:59:59pm.
Purpose The purpose of this milestone is to improve the robustness of our animal center(s).
Programming Task
The first goal is to investigate and address test failures in milestones E2, E3, and 6.
The next is to revise the STBU implementation to conform to the OTP philosophy and best practices:
Revising your implementation of the shelter and clinic interfaces to be based on GenServer;
Deploying supervision to ensure one fault doesn’t break the entire system;
State management to prevent faults from causing data loss; and
Creating an Application that encapsulates the system.
4.1 Using OTP Abstractions
In other words, your implementation should no longer directly spawn processes. Instead, process behavior should be defined in terms of an OTP abstraction and then instantiated via that abstraction (such as the GenServer.start/3 or GenServer.start_link/3 functions).
4.2 Supervision
One malformed message or buggy function shouldn’t take down the entire adoption/clinic service for every client. In addition to our efforts to eliminate such errors from our system, we must also face the reality that we are (almost) never 100% confident in the absence of such faults. To deal with the situation, we will employ the OTP notion of supervision: watching over the health of the processes in our system and restarting them in the event of a failure.
Every process you create should be under the watch of a supervisor. That need not mean that the process must be restarted when it fails; refer to the child :restart options. You are also encouraged to remove any defensive programming you may have done in your solutions for the previous milestones.
4.3 State Managment
We can restart our processes when they crash, but their state will be lost. In some cases, that is OK; however, it would be quite unfortunate if all of the pets remaining at the shelter "disappeared" before finding their forever home (or if a client had to re-schedule their appointment). Such critical information should be insulated from the cycle of crashing and restarting that may occur with supervised processes.
On the other hand, the state of some processes has a more transient flavor that doesn’t seem to call for such care. For example, losing the progress of a PetViewer through the shelter or a client’s currentVet selection causes no lasting harm.
The status of each pet in the shelter (available, playing, or adopted) should never be lost.
Likewise, booked appointments and currently reserved slots must be maintained.
If a client process exits for any reason, any PetViewer or AppointmentScheduler that it is interacting with should immediately perform any necessary clean up (like releasing a reserved-but-not-yet-booked appointment) and shutdown as well.
If a PetViewer or AppointmentScheduler process crashes, some other process should detect the failure and immediately perform any necessary clean up. The process should not be restarted, since:
Clients are left to deploy their own solution to monitor the status of their PetViewer/AppointmentScheduler process.
Devise a solution for your system to meet these goals. You may wish to draw inspiration from the key-value store example from class or the Stash from chapter 18 of Programming Elixir (see Readings).
4.4 Application & Client Interface
Finally, let’s package the system as an Elixir Application. Configure your project as an application named :stbu. When the application starts, it should initialize both the shelter and clinic processes and any related supervisors/helpers.
To configure the system, the application should read two items from its environment:
:config, whose value is an io_device as in previous milestones; and
:timeout, whose value is the number of milliseconds to impose as timeout on the various client operations.
To reflect the center’s status as an application, we will modify the client interface to the shelter and clinic in the following manner:
Provide STBU.Interface.Shelter.whereis/0 and STBU.Interface.Clinic.whereis/0. These functions return the (current) PID of the shelter process and clinic, respectively.
- Provide variants of existing functions that do not require being passed the shelter/clinic’s current address:
STBU.Interface.Shelter.view_pets/0 to go along with STBU.Interface.Shelter.view_pets/1.
STBU.Interface.Shelter.import_animals/0 to go along with STBU.Interface.Shelter.import_animals/1.
STBU.Interface.Clinic.request_appointment/1 to go along with STBU.Interface.Clinic.request_appointment/2.
The STBU.Interface.Entry interface may be ignored/removed.
4.5 Delivery
Your project should include the designated modules under the lib directory
(see —