Friday, December 27, 2019

12c SOA - Oracle Mediator part7 - Sequential vs parallel routing rules

A routing rule can be executed either in parallel or sequentially. To specify an execution type for a routing rule, select the Sequential or Parallel execution type in the Routing Rules section.

Basic Principles of Sequential Routing Rules:

  • Mediator evaluates routings and performs the resulting actions sequentially. Sequential routings are evaluated in the same thread and transaction as the caller.
  • Mediator always enlists itself into the global transaction propagated through the thread that is processing the incoming message. For example, if an inbound JCA adapter invokes a Mediator, the Mediator enlists itself with the transaction that the JCA adapter has initiated.
  • Mediator propagates the transaction through the same thread as the target components while executing the sequential routing rules.
  • Mediator never commits or rolls back transactions propagated by external entities.
  • Mediator manages the transaction only if the thread-invoking Mediator does not already have an active transaction. For example, if Mediator is invoked from inbound SOAP services, Mediator starts a transaction and commits or rolls back the transaction depending on success and failure.
Basic Principles of Parallel Routing Rules:
  • Mediator queues and evaluates routings in parallel in different threads.
  • The messages of each Mediator service component are retrieved in a weighted, round-robin fashion to ensure that all Mediator service components receive parallel processing cycles. This is true even if one or more Mediator service components produce a higher number of messages compared to other components. The weight used is the message priority set when designing a Mediator service component. Higher numbers of parallel processing cycles are allocated to the components that have higher message priority.
How the Parallel Routing rule works:




By using parallel routing rules, services can be designed to be truly asynchronous. However, the service engine executes these requests in a rather unique fashion.

Let's say you have 3 mediator services deployed to your SOA server and each of these has a single parallel routing rule. When the mediator service received a message,

  • The message would be inserted in Mediator store by the dispatcher.
  • Its message metadata would be written to the MEDIATOR_DEFERRED_MESSAGE table.
  • The payload goes into MEDIATOR_PAYLOAD table. 
All these would occur on the original calling thread.

The mediator service engine has one thread called Locker thread. The locker thread would surface the message metadata from the MEDIATOR_DEFERRED_MESSAGE table into an internal memory queue. The locker thread does this in its own transaction. The MEDIATOR_DEFERRED_MESSAGE table also has a state listed below:
0 – READY
1 - LOCKED
2 - COMPLETED SUCCESSFULLY
3 - FAULTED

Hence, it is important to understand how the locker thread works behind the scene, as this would affect your design decision:

The locker thread has an algorithm to process the message stored by the dispatcher, and there is only 1 locker thread per managed server. After the dispatcher has stored the message data in the MEDIATOR_DEFERRED_MESSAGE table, the locker thread will lock message(s) that has a state=“0”, the number of messages to be locked by the locker thread will be dependent on the Parallel Maximum Rows Retrieved parameter that you have set in the EM->SOA-INFRA->SOA Administration->Mediator Properties. The locker thread will cycle through 1 mediator component at a time and check if there are any requests to process from the internal queue. It will process the message(s) by changing its state to “1” for that component for processing and then sleep for the configured interval defined in the "parallel locker thread sleep" setting before moving on to the next mediator component. If it finds no message to process, it would move on to the next, and the next, until it loops back to the first composite, where it would then process its next request.


For example: If there are 3 mediator components m1, m2, m3 with priority 1, 2, 3 then the algorithm goes as lock m1 -> sleep -> m2 -> sleep -> m3 -> sleep -> m2 -> sleep -> m3 -> sleep -> m3, in 6 iterations of locker thread, m1 messages are locked once, m2 messages are locked twice and m3 messages are locked 3 times as per the priority. All this happens in a single Locker cycle. Only after the locker thread locks the retrieved messages will they be queued for the worker threads to process the messages. So if you have many mediator components (e.g. 50 mediator components) with parallel routing rule, it will take a considerable amount of time for the locker thread to lock the message to complete one locker cycle. If you have mediator components with lower priority, it will take a longer time for the locker thread to lock the message for the low priority mediator component. The locker cycle will be reset if you undeploy or deploy a new mediator component with parallel routing rules, this is to ensure the mediator component with higher priority will be processed in the next cycle.  You will be able to observe these behaviors when you set the logging level to the Trace:32 FINEST level in Oracle Enterprise Manager Fusion Middleware Control.

oracle.soa.mediator.common

oracle.soa.mediator.service

oracle.soa.mediator.dispatch

oracle.soa.mediator.serviceEngine


After the locker thread locked the message, the worker thread will retrieve the message from the in-memory queue and process the message. The number of worker threads can be tuned by changing the Parallel Worker Threads property in EM->SOA-INFRA->SOA Administration->Mediator Properties. Once the message is processed, the worker thread will change the state of the message to either “2” –Completed successfully or “3” – Faulted.

The engine was designed in order to prevent starving of threads caused by load on a single composite. What the engine wants to avoid is that, if you have a Mediator service that has received hundreds of thousands of requests and another one having received two requests, each service is given a fair amount of time to be serviced, otherwise the two requests may have to wait for hours to execute. Thus, the three settings to consider in asynchronous Mediator services are the following:

The Parallel Locker Thread Sleep setting: This is defined at the Mediator Service Engine level
The number of threads allocated to the Mediator Service Engine: This is defined by the Parallel Worker Threads parameter

The Priority property: Which is set at design time and applicable only to parallel routing rules

Another important point to note is when a mediator service engine is started, it registers itself in the database table called MEDIATOR_CONTAINERID_LEASE and gets a container ID. This is important because when the row is inserted into the MEDIATOR_DEFERRED_MESSAGE table, it round-robins the deferred message to one of its containers, the engine will then assigns the ID of the container that should process the message.

 List of design considerations designing your composite using mediator parallel routing rules:
  • The priority property is only applicable to the parallel routing rules, so you need to consider the mediator component priority base on your business requirement.
  • The locker thread will cycle through all mediator components with parallel routing rules deployed in your environment regardless of whether it has been retired or shutdown.
  • Use sequential routing rules if latency is important and that you are expecting the message to be processed without delay.
  • If you have well over 100 parallel mediator components deployed in your environment, the time to complete the locker cycle grew exponentially and could not be further tuned because there is only 1 locker thread and the lowest parallel locker thread sleep time that you can set is 1 second.
  • If you have a mediator component that contain both sequential and parallel routing rules, sequential routing rules will be executed before parallel routing rules.
  • Fault policy is only applicable to parallel routing rules only. For sequential routing rules, the fault goes back to the caller and it is the responsibility of the caller to handle the fault. If the caller is an adapter, then you can define rejection handlers on the inbound adapter to take care of the errored out messages, that is, the rejected messages.

12c SOA - Oracle Mediator part6 - Dynamic routing - Override a Static Routing Rule using DVM

"The basic idea behind dynamic routing is to separate the control logic, which determines the path taken by the process, from the execution of the process. Dynamic routing enables you to dynamically route messages at runtime from a mediator to multiple target services, based on the message content. You can use Domain Value Maps (DVMs) or Decision Components (Business Rules) to override static routes at runtime."

Dynamic Routing using DVM:

Use Case: There are two providers viz. Provider1 and Provider2 both of which are based on the same abstract WSDL. The Mediator has to invoke Provider1 or Provider2 based on the input. The logic for this mapping is:

If the input is Provider1 then invoke Provider1
If the input is Provider2, invoke Provider2

Create the composite where we will implement the Dynamic Routing via mediator. The composite contains a mediator(based on the Abstract WSDL we created earlier), a Service client and a Reference which points to the Provider1.





Open the mediator and click on Assign Values and map the input
 Now, click on Override. This will allow you to define a DVM that will be used for the routing. Enter the Name and Location of the DVM and then Set the values as shown in the screenshot below






Here we basically do two things:
Set the Value Expression and Key Domain: This allows the request input to be used as a key in the DVM
Set the feature we want to override: For this case, we override only the EndpointURI. For values that are not to be overidden, set it to <<Not Override>>.
When we chose DVM for the routing, JDeveloper creates the DVM and auto-populates the rows. For our use case, we require only the Keys and the endpointURIs (which we have mentioned as the value to be overridden) .

 Assign the sync reply part.
Deploy and Test
Input is provider1 and provider1 service invoked.


 Input is provider2 and provider2 service invoked.


Thursday, December 26, 2019

12c SOA - Oracle Mediator part5 - Error Handling

Use Case : When there is any mediator error, Using fault policy and fault binding, publish the error details into a JMS Queue.

Read Previous blog 12c-soa-oracle-mediator-part4-error-handling for more details.

Create a Distributed Queue and connection factory.
















 Add  JMS Alert action

 Add a Header value.
 Create required Properties
 Provide Destination and CF details.
 Press ok.

 Select the created JMS Alert.
 Deploy and test. The mediator failed and stored into the Queue.


Error message:
<commonfault xmlns="http://schemas.oracle.com/soa/fault">
<faultID>1560021</faultID>
<flowID>1730097</flowID>
<compositeDN>POC/MediatorFaultPolicyProject!1.0</compositeDN>
<componentName>MediatorFaultpolicyCheck</componentName>
<errorCode> 3302</errorCode>
<engineType> mediator</engineType>
<faultName> {http://schemas.oracle.com/mediator/faults}mediatorFault</faultName>
<faultType> SYSTEM</faultType>
<message>ORAMED-03302:[Exception in oneway execution]Unexpected exception in one-way operation &quot;execute&quot; on reference &quot;MediatorResequencerProject&quot;.Possible Fix:Check whether the reference service is properly configured and running or look at exception for analyzing the reason or contact Oracle Support Services. Cause: oracle.j2ee.ws.client.jaxws.JRFSOAPFaultException: Client received SOAP Fault from server : The composite &quot;POC/MediatorResequencerProject!1.0*soa_0ad97452-27c1-4e45-afa0-6993a0abc094&quot; is retired. New instances cannot be initiated.</message>
</commonfault>

Fault policy:
<?xml version="1.0" encoding="UTF-8"?>
<faultPolicies 
    xmlns="http://schemas.oracle.com/bpel/faultpolicy"
    xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
    xmlns:bpel1="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
    xmlns:bpel2="http://docs.oasis-open.org/wsbpel/2.0/process/executable"
    xmlns:medns="http://schemas.oracle.com/mediator/faults"
    xmlns:rjm="http://schemas.oracle.com/sca/rejectedmessages">

    <faultPolicy id="policySet">
        <Conditions>
            <faultName name="medns:mediatorFault" xmlns:medns="http://schemas.oracle.com/mediator/faults"
                       description="All Mediator faults">
                <condition>
                    <test>contains($fault.mediatorErrorCode, "TYPE_ALL")</test>
                    <action ref="default-termination"/>
                    <alert ref="jmsProperties"/>
                </condition>
                <condition>
                    <action ref="default-termination"/>
                </condition>
            </faultName>
        </Conditions>
        <Alerts>
            <Alert id="jmsProperties">
                <JMS propertySet="jmsPropertySet">
                    <Headers>
                        <property name="MSG_ID">1</property>
                    </Headers>
                </JMS>
            </Alert>
        </Alerts>
        <Actions>
            <Action id="default-termination">
                <abort/>
            </Action>
            <Action id="default-human">
                <humanIntervention/>
            </Action>
            <Action id="default-java">
                <javaAction className="oracle.integration.platform.faultpolicy.IFaultRecoveryJavaClass" defaultAction="default-termination"/>
            </Action>
            <Action id="default-replay">
                <replayScope/>
            </Action>
            <Action id="default-rethrow">
                <rethrowFault/>
            </Action>
            <Action id="default-ws">
                <invokeWS  uri="WebServiceURI"/><!-- format - <Absolute wsdl path>|service name|port name -->
            </Action>
            <Action id="default-enqueue">
                <enqueue uri="QueueURI"/> <!-- QueueURI format  - jdbc:oracle:thin:@<host>:<port>:<sid>#<un>/<pw>#queue -->
            </Action>
            <Action id="default-file">
                <fileAction>
                    <location>FOLDER_LOCATION</location>
                    <fileName>FILE_NAME</fileName><!-- FILE_NAME will support %ID%(rejected message instance id) or %TIMESTAMP% wildcards -->
                </fileAction>
            </Action>
            <Action id="default-retry">
                <retry>
                    <retryCount>3</retryCount>
                    <retryInterval>2</retryInterval>
                </retry>
            </Action>
        </Actions>
        <Properties>
            <propertySet name="jmsPropertySet">
                <property name="jmsDestination">jms/SOAErrorQueue</property>
                <property name="connectionFactory">jms/SOAErrorQueueConnectionFactory</property>
            </propertySet>
        </Properties>
    </faultPolicy>
</faultPolicies>


Featured Post

11g to 12c OSB projects migration points

1. Export 11g OSB code and import in 12c Jdeveloper. Steps to import OSB project in Jdeveloper:   File⇾Import⇾Service Bus Resources⇾ Se...