Ideally, in a production system, everything works perfectly. Services never mysteriously crash, free memory is constantly available, and CPU load rarely spikes above 50%. Unfortunately, this is not always the case.
Recently, a client was having issues with their site going down, consistently. They knew it was due to the redis service stopping, but didn’t know how to fix it. As a result, one person was perpetually on call, waiting for the site to go down, to run a simple sudo service redis restart.
While it won’t fix all of your problems, monit will buy you time, and your sysadmins sleep.
This process creates a configuration file, and adds the command monit to the path.
Configuring Monit
Monit config files are located in different places depending on the system. Ubuntu’s config file is located at /etc/monit/monitrc, whereas CentOS uses /etc/monitrc.
Monit config files follow a simple structure, of the form
12345
check process $processName with pidfile $pidfilePath
start program = $commandToStart
stop program = $commandToStop
if failed host localhost port $portNumber then restart
$timeoutConditions
As an example, below is how we have configured monit to watch redis on a CentOS box that was having memory issues, causing redis to force quit.
12345
check process redis-server with pidfile /var/run/redis/redis.pid
start program = "/etc/init.d/redis start"
stop program = "/etc/init.d/redis stop"
if failed host localhost port 6379 then restart
if 5 restarts within 5 cycles then timeout
In general, monit is a good tool to have in place. Though hopefully it is rarely needed, it prevents issues where someone is called at 3am in order to run a simple command, due to a service crash.
When we need to test a part of our application that fetches data
from a server, we will want to avoid making that request so as
not to slow down our tests; and because that endpoint might not
be implemented yet. Besides, we are focusing on unit tests, and they
should only test individual indpendent units. If our test makes an external
request, then it stops being a unit test and starts to venture into
the realm of integration or functional tests.
This method calculates the total rate based on how many hours worked and the hourly rate. The hours is fetched via
an XHR request. Testing this can be a little challenging, but not impossible. We can use sinon to stub
the collection’s fetch function:
While this will work, there are a couple things that should bother us. First, the RateCalculator
is tightly coupled to TimeEntries collection; but most importantly, the RateCalculator is doing too much.
It is retrieving the data AND calculating the rate. We can address this by ‘injecting’ the TimeEntries
into the calculate method:
If we step back for a moment, we can see that we might stumble on the same problem again. Consider
testing some part of our application that uses RateCalculator. We might have some code similar to this:
If we need to use RateCalculator in other parts of our application, we will duplicate this in many places
and lose track of it. Why is this bad again? Because it couples our application to Backbone and creates
some unmaintainable code. It will be difficult to change this if we ever decide that maybe Backbone is not
the right choice, or if our TimeEntries is a more complex collection
We can solve this by injecting the collection, like we did in the first scenario, and it is the route
I would take; but we will reach a point where passing the collection like a hot potato will not save us,
and we will have to deal with this situation head on.
And what about situations where we would want to trigger an action when a new set of collections is fetched?
Or maybe we have a real-time dashboard that needs to get updated on near real time every time some event
happens somewhere else (even on a remote computer or server)? How do we handle error messages for all xhr requests?
What about scenarios where the xhr response does not fit nicely with our collections and entities? For example,
suppose we need to request data about ‘things to do’ and the structure of that data returned is something like:
If we step back for a bit, and imagine our application as a vulnerable kernel that needs to be shielded from any
outside infection, then we can see how allowing direct calls to Backbone.Collection#fetch() deep in our application
exposes it to external factors. Changes to the Backbone API can require massive changes deep in our application’s
kernel.
We can take some inspiration from the ‘Hexagonal Architecture’ to help us come up with a ‘cleaner’ solution.
In order to access any external system (like xhr requests), we need to add an interface for it.
We might want to start by defining the interface:
12345678910111213141516171819
describe'Time Entry Repository',->describe'Configure the end points'it'When end points are not uniform',->repository = newTimeEntryRepositoryget: '...'post: '...'put: '...'list: '...'expect(repository.getURL()).to.be'...'expect(repository.postURL()).to.be'...'expect(repository.putURL()).to.be'...'expect(repository.listURL()).to.be'...'it'When end points are uniform',->repository = newTimeEntryRepositoryall: '...'expect(repository.getURL()).to.be'...'expect(repository.postURL()).to.be'...'expect(repository.putURL()).to.be'...'expect(repository.listURL()).to.be'...'
Our repository makes provisions for cases where the url does not fit nicely with Backbone’s
expectations. Backbone expects all urls to be the same and the only thing that changes
is the http verb. There might be cases where that is not possible.
Fetch API
Now we can specify how we will fetch data from the server:
123456789
describe'Time Entry Repository',->describe'Fetch API',->describe'When it fetches data from remote server',->it'then makes an xhr request',->xhrMock = sinon.mock($,'ajax').returns({})repository = newTimeEntryRepository()repository.all('http://a.url/timeEntries')expect(xhr.calledOnce).to.betruexhrMock.restore()
This test only needs to ensure that an xhr request is made with jquery. It is testing the
repository’s internal implementation, which consequently makes it very fragile. However, an object like
this lives in the periphery of an application and for them these kinds of tests are common. We will later
see how it makes our domain logic much cleaner. In the meantime, we can make this test pass:
Our fetch function could have also used a backbone collection. The clients using the repository won’t know
nor need to know how it is implemented. But this still looks a little wonky. We haven’t gotten anything benefits
from it… yet.
Now lets consider a scenario where we’d like to promisify our interface:
12345678910
describe'When it fetches data from remote server',->it'then it returns a promise',(done)->xhrMock = sinon.stub($,'ajax').returns([1,2,3,4,5])repository = newTimeEntryRepository()repository.all('http://a.url/timeEntries')then(timeEntries) ->expect(timeEntries.length).to.be5done()xhrMock.restore()
This is a contrived example, but bear with me for a while. We return an array of 5 items and we need to tell
mocha that this is an async test. We do this by passing done as an argument to the test and then invoking
done() to notify mocha that the async test has finished. We can then make assertions on the value of the
promise. Our specs now start to look more like production code. The only inconvenience at the moment is
creating some fake data. But we can live with that. Much better than coupling all our tests (and production
code to jquery). And we don’t need to change anything in our code to make this pass because $.ajax() returns
a promise.
This is okay for very simple cases, but what if we need to return something with behavior (an instance of an object):
12345678910
describe'When it fetches data from remote server',->it'then it returns a promise',(done)->xhrMock = sinon.stub($,'ajax').returns([1,2,3,4,5])repository = newTimeEntryRepository()repository.all('http://a.url/timeEntries')then(timeEntries) ->expect(timeEntriesinstanceofTimeEntries).to.betruedone()xhrMock.restore()
We introduced the Q library for dealing with promises (a matter of personal preference). Our clients don’t need
to know what library is being used, they just need to know its a Promises/A+ compatible library. So we should be
able to substitute the Q library for Bluebird if we need to and any client of this class won’t need to change.
Notifications
We can now even start introducing custom events that our application can listen to. An event for fetching data, or
for creating a new entity, deleting one or updating one; can be triggered for any part of our application to
listen to:
12345678910111213141516
describe'Time Entry Repository',->beforeEach->@caughtEvent = false@aRemoteObject =listen: (repository) =>repository.onFetch=>@caughtEvent = trueit'Trigger an event when entries are fetched',(done)->repository = newTimeEntryRepository()repository.all('http://a.url/timeEntries')xhrStub = sinon.stub($,'ajax').returns([1,2,3,4,5])@aRemoteObject.listen(repository)repository.fetch()expect(@caughtEvent).to.betruexhrStub.restore()
Now any part of our application can listen directly for any events triggered by the repository and execute
a function accordingly. This enables us to update different parts of our UI independent of each other. We can
also test those parts our application pretty easily by just triggering the event without needing to wire up
the entire repository:
1
repository.vent.trigger'fetched'
In some cases, we might only need to create some fake time entries, but that is to be expected.
Handling Network Failures
This strategy can also enable us to handle network errors in a generic manner. If our app is a single
page app that is expected to be kept running on the browser for long periods of time (even days or weeks),
whenever the network is down or an xhr request failed for some other reason, we should be able to notify the user.
Although we can do this with Backbone by overriding sync, it feels like a hack and I am always wary of
overriding third party libraries.
To handle network failures for all xhr requests we would either need to implement that code in every repository,
or use inheritance (or mixins also). We’ll use inheritance in this case since it is something only
repositories will need to do:
We can handle errors with promises by passing in a function as an error handler to the then() method.
We could also have an application event bus which we can notify of any errors from within this error handler:
We can use the Repository Pattern to decouple our application from any framework specific code that can
make our application hard to test. As a secondary benefit, our objects become more focused by having only
one primary reason to change if all they do is just concern themselves with fetching and sending data.
Promises can also be used to make our code more readable when dealing with async operations. They also help
us deal with error handling in an elegant manner. Finally, the use of a messaging pattern and an event bus
helps us keep the components of our application decoupled by enabling us to send messages to remote objects
without having to hold a direct reference to them. We can then test these objects in isolation without
having to wire up a large object graph.