Almost two years ago, I wrote a java service for relaying and replicating some communication protocol for an American customer.
One of the requirements of that service was to have persistence for the protocol commands it was passing, so in case of a communication failure, it would repeat the signal over and over until it got through. The file persistence was to ensure that if the service itself crashed for some reason, it would be able to pick up on the same note without loosing a thing.
The design was fairly simple, an array of producer/consumer queues, each accommodating a two way communication path to a far away server.
Even though I had a very short time to develop and deploy this service, I was anal enough to make myself a very nice persisted queue implementation.
I used generics for the object that represents a single communication element. I used it naively by applying a string in the service I was writing, but I did see others use it in more elaborate fashions.
Because of some problems I had with using the Log4J implementation, I wrote my own logging mechanism. I did this since Log4J creates a drizzle of a memory leak when the implementation constantly adds categories and appenders at run-time. I figured that out while load testing, where I bombarded it with new sessions, I’ve notices that the log4J accumulated all the session appenders and never cleared them out. To smooth things out, I wrapped the logging implementation with a comfortable delegator, which allows an easy substitution; thus, my persisted queue was initiated either with log4J or by any other implementation (i.e. my own).
The way I made the persistence stick was to have a transaction like de-queue sequence. In lighter terms, what I mean is that once a message is de-queued by the consumer, it isn't removed from the queue and the persistence file, until a complimentary “commit de-queue” message is sent. I supplemented this with a regular de-queue method and a remove method that bypassed the FIFO mechanism all together.
I worked hard on making it as simple to use as i could. The base line initialization was without anything special, and was simple as calling a constructor without any arguments and would result in a simple blocking queue. That meant that nobody had to learn anything special about it, unless of course a special feature was actually required. The hard part is to overcome ones own bias to ones own code.
I’ve finally realized I’ve struck gold with this, one day when I was re-factoring some packages and notices that this module was being used all over the application.
I was mirthful and jolly
One of the reasons for my tipsy reaction was that while writing this little component, I did right and took the time to make a generic reusable module. It’s sometimes hard to tell while writing something new, whether it would ever be in use again. The academic approach of having everything reusable, is a fine methodology, but does have drawbacks when a customer is breathing down your throat, and doesn’t exactly appreciate paying for the reusability of the code.
Sometimes one just gets plain old lucky.