10

Problem

I have to build a reliable integration. This means that external callouts should be delivered even if the remote SOAP webservice is down. (when the ws is online)

The idea is to keep the callouts messages if the webservice is down and will retry to send them after some time.

Background

Thinking on the solution I noticed some important facts:

  • The order of sent messages should be respected
  • There are more than one external method
  • The sent record data should be the current data, not the data when the callout was trigger.
  • I have a dummy remote method to check the WS availability
  • The response should be asynchronous (CallBack WS)
  • I can't use outbound messages

Approach

My approach is to insert the message to send into a queue and consume it from a scheduled job. The stored message will have:

  • recordId in order to get the current data
  • message type in order to know which remote method will be called
  • extra data (JSON serialized) to add some useful context
  • timestamp

When the cron is executed I planning something like this:

kill schedule  // to avoid more than one consumer
msgs = [select from queue order by timestamp asc limit 200] //limit to ensure bulk-safe 
if !msgs.empty
   if WS.isAvailable // check the remote webserver
      for(m:msgs)
         switch m.type
            case typeA
                 ws = new WSA(m.id,m.extraData); //instance the WS wrapper
            case....

         ws.send(m); // I'll explain this later
         consumed.add(m); // to remove later on queue

      delete consumed
schedule job

WSA, WSB, .. will extends from WS

class WS{

  abstract getData(); // this will retrive the needed data using the record Id
  abstract callRemote(); // this will instance and call the remote ws

  public static send(){
     this.getData();
     this.callRemote();
  }

} 

This is a draw to illustrate the idea

enter image description here

Questions

  1. Can you see any problem on my approach?
  2. Have this approach any governor limitation? It is planned for Unlimited
  3. Is out there any better/simpler approach to build a 99.9% reliable integration (SF > WS SOAP) ?
  4. Could you suggest any improvement?

Update

I've discovered a possible problem: if queue.size() > 200 (I put that limit for soql limitation during the process) in the scheduled time. The queue keeps growing and never will be totally consumed.

How could I solve this?

  • Can you explain why can't you use Outbound Messaging, its entire reason for existing is to solve this exact problem. – superfell Nov 13 '13 at 16:11
  • @superfell They are asking for guaranteed transaction order, which I believe Outbound Messaging isn't subject to. Am I wrong on that? – sfdcfox Nov 13 '13 at 16:14
  • @superfell also I need to make Basic Authentication and endpoint WSDL, if I am not wrong Outbound Messages does not support that. – Martin Borthiry Nov 13 '13 at 16:30
  • If your sending current data, rather than data at queue insertion time, then what's the ordering getting you? – superfell Nov 13 '13 at 16:43
  • rather than rebuilding everything, could you build a listener bridge (i.e. use OM and have an intermediary do the translation/feature gap) – superfell Nov 13 '13 at 16:44
5

You can achieve the vision in the drawing. As I see it, you need the following pieces:

  • An abstract base class (WS) that the other classes will inherit from, or an interface, depending on the exact use of the other classes.
  • A scheduled class that executes periodically to check if the server is available, and if so, kick off a batch process.
  • A batch class (can be the same as the prior class-- they're just interfaces) that queries pending messages, and attempts to execute them; once completed, they can be marked as such.
  • A custom object that holds the queued data, which you can sort by creation date in order to guarantee transaction order.

There's no reason why the system infrastructure couldn't support this design model. It has an added level of robustness, because the normal Outbound Messaging system will discard messages that exceed a certain time limit (24 hours), and does not guarantee message order.


Can you see any problem on my approach?

It is ideally achievable, and probably easier to build than you realize.

Have this approach any governor limitation? It is planned for Unlimited

Batch methods only get to use 10 callouts per transaction, so you'll have to make sure you are setting the scope size appropriately. I'd probably save a "connection check" and simply try to execute the function-- if it fails, you can catch the exception and retry those messages later.

Is out there any better/simpler approach to build a 99.9% reliable integration (SF > WS SOAP) ?

In theory, a polling loop on the other server might be more efficient in the long term, but the salesforce.com infrastructure can easily support this logic for thousands or even tens of thousands of calls per day (or more). The guaranteed transaction order piece is what makes this proposed solution attractive.

Could you suggest any improvement?

The system should work perfectly well. The tricky part might be the actual implementation, but this is a sound design.

  • Thx for your faster reply. But, why do you suggest to check the connection before check the queue size? I think that it is more slower to make a callout than a SQOL Query. Isn't? – Martin Borthiry Nov 13 '13 at 16:34
  • I think you may have misunderstood. I suggested not checking for a valid connection. Simply query first, then try to post the data. Querying the queue should normally take <10ms unless it is really backed up. Skipping a connection check "to see if the server is there" increases the code efficiency by 10%. – sfdcfox Nov 13 '13 at 16:37
  • You are right I misunderstood, bought are thinking the same. – Martin Borthiry Nov 13 '13 at 17:20
0

To me, I think the type of information and how it's being used could shape the way this is done as well.

I'd like to broaden this discussion slightly. The way I see it there are two other approaches you could use. They may not be appropriate, but worth talking about at least.

  1. User re-try
  2. Outbound Messages re-try

User re-try

In the User re-try approach, the codebase is really simple because if the endpoint is down or the User receives a failed response, they're informed immediately. It is therefore 'reliable', but probably not in the way you mean.

This obviously only works if it's a process driven by a User, such as submitting a Visualforce form to an external system. The User can re-try, then inform the appropriate people if it continues to fail.

It's not overly user friendly, but if the endpoint is up nearly all the time, and the User is generally an internal (staff) person, it drives down development costs significantly.

Outbound Message re-try

I know you said you don't want to use an Outbound Message because you can't guarantee the transaction order, however in an implementation we did years ago, we essentially used an Outbound Message as a trigger to an external system and 'Virtualised' the order of delivery.

When a certain event happens, a custom object record is created with appropriate information that triggers an Outbound Message via a Workflow Rule. The endpoint receives the Outbound Message and then it decides what it does with that information. In our case, the external system would use that trigger to then query Salesforce for all records that are relevant. The record includes a date/time and perhaps you include a type or other information that might help, then the external system knows which order to process the relevant records. Once it's complete, the external system updates the records as complete and the next time it receives a trigger it ignores those records.

The beauty of this is it uses standard Salesforce functions/re-try, no real custom coding in Salesforce, but it does shift the complexity to the external system. You also should have some monitoring to ensure all Outbound Messages are received before the 24-hour re-try window. (although I think you have bigger problems if your endpoint is down for 24 hours at a time)

There are a few ways to re-trigger the Outbound Message if the endpoint is down for 24 hours, such as time-based workflow, schedule jobs, or a simple dashboard for Users to monitor.


Just thought I'd add these two other approaches so they can at least be discussed. They've both worked for me in the past, but it also depends on other factors as to whether they'll be appropriate for any given implementation.

  • Thank you for your extended new point of views. However, In my case is not possible to modify the external service. So, I found some issues to your approach: I think Outbound messages has many limitations, not only order login. As far as I know it is not possible to use Basic Authentication and also external WSDL is not supported. About User re-try (I've used this before successfully) is not possible, because the user is not the only trigger to the external call, there are batchs,cronjobs and others actors involved. – Martin Borthiry Nov 14 '13 at 13:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.