Recently I was working on a couple of applications for a client. One application was a bridge to integrate a PPC campaign run by another vendor, and the other application was a backoffice point of sale system for processing client orders while applying a set of complex business rules.
As the code was becoming more complicated I was having to add more error checking code to deal with the random Infusionsoft API errors that we discussed in this thread on the Infusionsoft API Developer’s forum and brought up originally in the old forums here and here.
Dom Cassone started the thread by observing that a script he had in place for some 2 years had been executed over 725 times, but that 28 times (3-4% of the times) the script had not run, and included his script for reference. As it turns out, there is a bug in the Infusionsoft server stack that causes intermittent API errors. The symptom of this is bug is that you can silently lose data and transactions will fail to execute when using the API if you’re not doing proper error checking and handling.
There are several classes of errors that happen in an API call. There are permanent errors, and there are transient errors. The documentation makes no mention of this, and it was something I discovered only through testing. Permanent errors can be caused by problems on the client side (passing invalid data) or on the server side.
In this case, the Infusionsoft XML-RPC API server will respond to a perfectly valid API call with a fault code (500) and the message:
Server encountered exception: java.lang.IllegalStateException: Cannot create a session after the response has been committed
A little research turned up this Java JIRA bug report which describes the error and some of the situations that can cause it to happen. This is evidently an internal server problem in the Infusionsoft server code with how they handle buffers and sessions in Tomcat. I suspect this is also the same bug that causes the web interface to come up blank or with mysterious errors every so often.
The XML-RPC client API actually handles this properly by notifying the iSDK of the error. Unfortunately the iSDK doesn’t handle it very intelligently. Older versions of the iSDK just kill the whole script by default (Very Bad). I believe new versions silently pass the error back to the developer’s function as the return value (better). Unfortunately their documentation and examples are all written to assume that valid calls always succeed and that all errors are permanent and fatal. Since many developers are used to very reliable API’s like MySQL, this often goes unchecked.
I had dealt with this before by disabling the script killing, and writing checks for it. In the spirit of DRY I decided to tackle it by moving the fixes into the iSDK itself to make my code cleaner, more reliable and easier to maintain.
Fortunately the iSDK is also written this way. All function calls to the server pass through a function called “methodcaller”. This function is called by all iSDK functions, and it hasn’t changed through any version of the iSDK, making it a prime candidate for replacement. In my code I actually define it in a subclass of the iSDK so that I don’t have to alter the iSDK directly, and so that I can drop in new releases of the iSDK very easily.
The replacement detects and catches the temporary errors and then does a backoff, and retries the transaction. If the error is a known permanent error, then it does not retry the call in order to minimize API usage. For unknown or temporary errors, I set it to retry 3 times before giving up and passing the error back to the caller. So far I have never had it need to retry the call more than once. There’s also an option to send email notifications with the failure details so you can monitor what’s happening, and whether or not the retry succeeded, and how many retries it took.
I’m using this code in production on my client sites for the past few weeks and it has pretty much eliminated some mystery missing data problems we were having, and made some more complex transactions that were using many API calls in a row work reliably.
If you’d like a copy of the i2SDK please signup below.