|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 6 of 7
If code is atomic and stateless, it may take on other attributes, like idempotence. If a method is idempotent, you can execute it repeatedly and get the same outcome without adversely affecting anything else, like state.
Wikipedia defines idempotence in computing thusly:
In computer science, the term idempotent is used to describe methods or subroutine calls that can safely be called multiple times, as invoking the procedure a single time or multiple times results in the system maintaining the same state; i.e., after the method call all variables have the same value as they did before.
Example: Looking up some customer's name and address in a database is typically idempotent, since this will not cause the database to change. Placing an order for a car for the customer is not idempotent, since running the method/call several times will lead to several orders being placed, and therefore the state of the database being changed to reflect this.
In Event Stream Processing, idempotence refers to the ability of a system to produce the same outcome, even if an event or message is received more than once.
Idempotence in a method or function is not always possible. While some logic lends itself naturally to idempotence, other logic may require safeguards in its design to assure safe repeatability.
If your code can be made idempotent, you'll have a lot of flexibility in executing that code across a distributed environment like the cloud. By their natures, some distributed environments expect failure and are designed to work around it. Consider how the Internet routes around failure. If I request a Web page through my browser, and the request fails due to a backhoe cutting a trunk line in Des Moines, I can hit reload and my second request will likely take a different route to get the page. I could probably request that page repeatedly and not affect anything (though I may be driving up someone's ad-based revenue). That's idempotence in action in a distributed environment where failure happens and the environment deals with it.
In Listing 4, you have an example of a class that accumulates the total tax on an order. Each time addToTaxTotal() is called, the member variable totalTax is destructively incremented. Though the class handily wraps up the tax value, there is no way to get back to a prior value
if an error condition occurs. Calling addToTaxTotal() multiple times with the same inputs will yield different results because the method does not leave memory in the same state.
Therefore, by definition, this method is not idempotent. (Ignore for the moment the fact that there is a dependence on state
here, since those arguments were covered earlier.)
package com.appistry.samples;
public class NonIdempotentTaxCalculator {
private float totalTax;
public void addToTaxTotal(Item item, String zip) {
totalTax += lookupTax(item.getValue(), zip);
}
}
In Listing 5, you have an idempotent class that, given the same inputs, always returns the same results. The IdempotentTaxCalculator takes an array of order items, and iterates over them using only local variables on the stack. No matter how many times calculateTax() is called, it will always return the same results given the same inputs.
package com.appistry.samples;
public class IdempotentTaxCalculator {
public float calculateTax(Item[] items, String zip) {
float tempTax = 0.0f;
for (Item item : items) {
tempTax = lookupTax(item.getValue(), zip);
}
return tempTax;
}
}
But what if you need to change state? How can you make a method that changes state behave idempotently?
First off, just saying the word state implies that you're keeping information somewhere. It might be in a shared database, a distributed cache, or a single, golden object somewhere in your system. If you have such state, then you can leverage it to your advantage. Listing 6 is somewhat oversimplified, but it conveys the general idea: design so that multiple calls can be absorbed without side effects. This concept is used in distributed messaging systems, and in any system where multiple calls for the same operation may arrive, but only one outcome is desired. The class in Listing 6 guards against repeatedly processing the same incoming order message by using the available state of order messages in queue.
package com.appistry.samples;
public class OrderProcessorService {
public synchronized void processOrder(Order order) {
if ( orderQueued(order) )
return;
enqueueOrder(order);
}
}
Many of the arguments for the value of idempotence are the same as those you've previously seen for atomic, cohesive, and stateless code running in distributed environments and on multi-threaded, multicore designs. Idempotent code's repeatable and non-destructive nature improves availability and makes load balancing easier. You can run the code on any thread or any node and not worry about side effects.
Reliability in a distributed computing environment like the cloud sometimes means that an execution step may be interrupted by hardware failure. In that event, the distributed environment may decide to repeat the execution step elsewhere. The repeatability of idempotent code is ideal in these circumstances because the method call can be repeated without worry and without dependencies.