Error Handling of Outbound Proxy Calls
Sometimes ago I wrote a weblog series about error handling in SOA scenarios especially when calling server proxies in inbound scenarios. I discussed features of NW Ehp 1 resp. 2 (Forward Error Handling – A short look at SAP Business Suite Ehp 4). Michal Krawczyk did the same in his SCN blog: PI/XI: Forward Error Handling (FEH) for asynchronous proxy calls with the use of Error and Conflict Handler (ECH) part 2. In this blog instalment I want to discuss the outbound scenario: In ABAP you can perform SOAP calls to Web Services outside the SAP system. Every ABAP server can perform this by calling client proxies. You don’t need a special middleware like SAP PI it although it makes sense if you consider administration and governance.
What are the use cases of client proxy calls:
- Passing data to an external system that persists those data.
- Retrieving results of a complex calculation performed in an external system.
- Implementation of asynchronous web services (server proxies) that give the result back using an outbound proxy call. In fact this is the recommendation how an SAP Enterprise Service for update/change services should work.
Please remark the latter scenarios can occur in online and batch processes, in every scenario (A2A, B2B and so on), and even in the case that an external system wants to read SAP data asynchronously which is sometimes done if an external system reads data from many data sources in an AJAX-like way.
This blog discusses only one topic: what should you do if a service call fails? This shouldn’t happen quite often if system administrators do a good job but it is possible in the following cases:
- The Web Service runtime of an ABAP system is misconfigured.
- The logical port of the client proxy is misconfigured. In this case the instantiation of the client proxy will fail.
- The external system isn’t reachable.
- The external system returns a SOAP fault message.
When looking deeper at this list we should distinguish the synchronous and asynchronous case:
- The error handling in the synchronous client proxy call is just the same as every other function module would call. We have to implement an error handling.
- In the asynchronous client proxy call we should expect that the called system has a forward error handling mechanism (see Forward Error Handling – Part 1: Outline) for explanation. By the way: the case that an external system isn’t reachable is easy to handle in an asynchronous scenario because the ABAP server has a local integration engine which can be switched on if you connect it to a PI (but you can switch it on and use it without external PI, too). In this case the outgoing message will be persisted in a queue after the end of a LUW (COMMIT WORK) and resend it afterwards using transactions of local integration engine (transaction SXMB_MONI).
A frequent error will be probably caused by a misconfiguration of the logical port of the client proxy in transaction.
A bad advice
Transaction SPROXY has a very good inline documentation that explains Web Service implementation and I really appreciate the depth of the explanations. Unfortunately there it contains one error that I believe SAP will correct soon. Let’s have a look at the inline documentation that explains how to call a client proxy:
Let’s have a deeper look at the last sentences:
Important Note: Consumer Proxy in Update Task
If the application data is persisted in an update task, then the XI outbound call also needs to be made in the update. Otherwise, if the update is canceled, the qRFC queue may become blocked due to the unscheduled update task. Since the queues are interlinked, this can have a significant effect on the whole of outbound processing.
This recommendation is obviously wrong and can’t work in synchronous client proxy calls that use result of the proxy call for own calculations. One reason is very simple: the update module is performed after the COMMIT WORK and has no access of the local memory of the application. But even in rare cases in which it could be possible you shouldn’t do it and I will explain you why in the next section.
Avoid complex code in update modules!
The first lesson every ABAP programmer learns is to keep an update module simple – it should be so robust that it is extremely unlikely that it will ever fail. We should keep the rule because of many reasons – please let me mention only a few:
- A robust application should ensure that after a COMMIT WORK every update is performed correctly.
- Crashed update modules are hard to analyze and to debug in transaction SM13. The user of an SAP transaction usually can’t do this.
- The error context is hard to analyze because it is not easy to see what a user who is using a SAP transaction wanted to do and what he was working on.
- The best applications give a user information about wrong input and other error situations so that a user can react which is not possible if the error occurs after end of LUW.
These are only a few reasons and I could write more about it: there are forbidden commands in update modules, you have to take care about the order execution (V1, V2 and V3) and the user context and so on but I don’t have to do because the lesson is simple: please avoid complex update modules!
The best update modules are short and simple and fit on a screen. They don’t call many modularization units and you can check within short time that there no forbidden commands within the codes and no harmful enhancements will ruin the execution.
A call of a client proxy is a very complex operation that shouldn’t be performed in an update task. Adding more business logic to an update module makes the situation even worse. That’s why I don’t consider this as a feasible programming model.
What should you do?
As I already mentioned above the case of synchronous calls is comparable to RFC call and this case is well understood so I don’t discuss it here.
At first let’s discuss the recommendation of SAP mentioned above for enterprise services:
If the application data is persisted in an update task, then the XI outbound call also needs to be made in theupdate. Otherwise, if the update is canceled, the qRFC queue may become blocked due to the unscheduled update task. Since the queues are interlinked, this can have a significant effect on the whole of outbound processing.
At first it is possible to persist the application data of an enterprise service in an update task and call the client proxy in the same LUW directly (i.e. outside a update module) and this is what you should do. If the client proxy is called asynchronously the scenario is very robust and only in case of misconfigured logical ports errors will occur. If you want to prevent misconfiguration you should work with UDDI and service groups resp. PI and those misconfiguration will become unlikely. Even if there are network problems or an external system is down all outgoing messages will be queued and can be resend later using transactions of local integration engine.
But how should your application react if an error (think of misconfigured local port) occurs so that the client proxy can’t be instantiated and the outgoing message can’t be queued in the local integration engine? in asynchronous scenarios I recommend to persist application data and to send the response resp. confirmation later as a retry with one of the following strategies:
- Use a Web Service error handling framework like AIF or ECH. It is no standard scenario in ECH but nevertheless possible.
- If the proxy call fails you can add the call to an event queue to perform a retry.
If you use an event queue (there are many of them: qRFC, bgRFC, BOR events for example) for a retry mechanism, you should ensure the following:
- The administration reports of the event queue make it possible to analyze even hundreds of errors and give the administrator a hint what to do (which logical port has to be reconfigured for example).
- The error messages should be standardized and meaningful.
- The administration reports allow performing mass retries and should allow a developer to debug the execution of an event.
This strategy can be feasible for sending unidirectional messages (informations and notifications), too, but you can also try to treat them like synchronous calls depending on the application context.
Let me summarize the most important recommendations of this blog:
- Try to avoid complex logic in update modules.
- Try to avoid complex logic in update modules even if SAP’s online documentation recommends it.
- Make your SOA application stable and robust using an integration engine. If misconfiguration is the most frequent problem (think of changes of external systems) then an enterprise service bus can prevent a chaos of P2P connections.
- When developing Enterprise Services get familiar with error handling tools like AIF or ECH.