The Eloqua API is carefully managed and throttled, and returns reponse codes with excellent information about the success or failure of your call.  Because of this, it can be very useful to wrap your calls to Eloqua in a way that elegantly responds to, and acts upon, the information returned.

 

Some calls to the API have throttling that only allows a certain number of calls per time period.  Given that many applications may be using the API for a given client at the same time, or many threads of the same application, it is often wise to look for the error message from this throttling function, implement a slight pause, and retry.

 

In the following code snippet, we perform a simple action against the API (listing members in a program builder step), but wrap it in a way that detects the error codes, responds accordingly, and allows your application to implement specific logic for password expiry, system maintenance, or other response codes.

 

This code snippet uses the typical SOAP service proxy that we set up in another article.

 

        public Member[] PerformListMembersInStepByStatusWithRetries(ExternalActionServiceClient programServiceProxy, int intPBStepID, ExternalActionStatus status, int intPageNumber, int intPageSize)

        {

            bool blnOkayToRetry = true;

            bool blnPasswordsExpired = false;

            bool blnSystemMaintenance = false;

            bool blnMaxConnections = false;

 

            int intRetryCount = 0;

            Member[] retrievedEntities = null;

 

 

            if (this.OkayForNextEloquaAPICall(APICallType.ListMembersInStepByStatus))

            { 

            while (blnOkayToRetry)

            {

                blnOkayToRetry = false;

                try

                {

                    intRetryCount++;

                    retrievedEntities = programServiceProxy.ListMembersInStepByStatus(intPBStepID, status, intPageNumber, intPageSize);

 

 

                }

                catch (Exception ex)

                {

                    if (ex.GetBaseException().GetType().FullName.IndexOf("OperationTimeIntervalFault") > 0)

                    {

                        blnOkayToRetry = true;

                    }

                    if (ex.GetBaseException().GetType().FullName.IndexOf("UnexpectedErrorFault") > 0)

                    {

                        if (intRetryCount < 5)

                        {

                            blnOkayToRetry = true;

                        }

                        else

                        {

                            blnOkayToRetry = false;

                            Trace.TraceWarning(String.Format("More than 5 Exceptions in EloquaInstance:PerformListMembersInStepByStatusWithRetries {0} :: {1}", ex.Message, ex.InnerException), "Exception");

                        }

                    }

                    if (ex.InnerException != null)

                    {

                        if ((ex.InnerException.ToString().IndexOf("Invalid Company, Username and Password Combination") > 0) || (ex.InnerException.ToString().IndexOf("Account is disabled") > 0) || (ex.InnerException.ToString().IndexOf("Account has been locked out") > 0))

                        {

                            //passwords have expired

                            blnPasswordsExpired = true;

                            blnOkayToRetry = false;

 

                        }

                        if (ex.InnerException.ToString().IndexOf("servers are currently undergoing maintenance") > 0)

                        {

                            //system maintenance

                            blnSystemMaintenance = true;

                            blnOkayToRetry = false;

 

                        }

 

                        if (ex.InnerException.ToString().IndexOf("exceeded the maximum number of concurrent connections") > 0)

                        {

                            //max connections

                            blnMaxConnections = true;

                            blnOkayToRetry = false;

 

                        }

 

 

                    }

                    if (blnOkayToRetry)

                    {

                        Trace.WriteLine(String.Format("Retry after 300ms"), "Information");

                        Thread.Sleep(300);

                    }

                    else

                    {

                        Trace.TraceWarning(String.Format("Exception in EloquaInstance:PerformListMembersInStepByStatusWithRetries {0} :: {1}", ex.Message, ex.InnerException), "Exception");

                        if(!blnPasswordsExpired && !blnSystemMaintenance && !blnMaxConnections)

                            throw;

                    }

                }

            }

            }

 

            if (retrievedEntities == null)

            {

                //error has occured, return a blank array

                retrievedEntities = new Member[0];

            }

 

            if (blnPasswordsExpired)

            {

              //specific handling code

            }

 

            if (blnSystemMaintenance)

            {

              //specific handling code

            }

 

            if (blnMaxConnections)

            {

              //specific handling code

            }

 

            return retrievedEntities;

        }

 

 

This code snippet uses a function of OkayForNextEloquaAPICall to implement an appropriate pause mechanism.  By passing in a calling type (which we have defined), we can implement pauses uniquely by type.  Query calls are generally the heaviest, and are therefore throttled the most.

 

 

        private bool OkayForNextEloquaAPICall(APICallType callingType)

        {

            int intPause = 0;

            System.TimeSpan diffResult;

            diffResult= DateTime.Now.ToUniversalTime().Subtract(dttLastEloquaAPICall);

 

            int intRequiredPause = 0;

            bool blnResetClock = false;

            switch(callingType)

            {

                case APICallType.Query:

                    intRequiredPause = 1000;

                    blnResetClock = true;

                    break;

                case APICallType.Update:

                    intRequiredPause = 0;

                    blnResetClock = false;

                    break;

                case APICallType.Retrieve:

                    intRequiredPause = 0;

                    blnResetClock = false;

                    break;

                case APICallType.ListEntityTypes:

                    intRequiredPause = 0;

                    blnResetClock = false;

                    break;

                case APICallType.ListMembersInStepByStatus:

                    intRequiredPause = 0;

                    blnResetClock = false;

                    break;

                default:

                    break;

            }

 

            while (diffResult < TimeSpan.FromMilliseconds(intRequiredPause))

            {

                intPause++;

                Thread.Sleep(100);

                diffResult = DateTime.Now.ToUniversalTime().Subtract(dttLastEloquaAPICall);

            }

            if(blnResetClock)

            {

                dttLastEloquaAPICall = DateTime.Now.ToUniversalTime();

            }

            return true;

        }