Showing posts with label Oracle Business Events. Show all posts
Showing posts with label Oracle Business Events. Show all posts

Tuesday, March 20, 2018

Asynchronous Business Event Subscriptions

Asynchronous Business Event Subscriptions - Troubleshooting Tips

Overview 

This blog is intended as an example to help trace an asynchronous business event through it's execution within the Workflow Business Event System. This blog should also help clarify the myth among Oracle Workflow developers and administrators that all business events can be traced through Business Event System AQs.
As a reader of this blog post, it is expected that you understand following steps already.
  • Create a business event using Workflow Administrator Web Applications responsibility
  • Create subscriptions to business events
    • Synchronous subscriptions with phase <= 99
    • Asynchronous subscriptions with phase >100
    • Understand "On Error" subscription attributes such as "Stop and Rollback" and "Skip to Next"
It is strongly recommended that all business events and/or groups that has at least one LOCAL or EXTERNAL subscription should also have one ERROR subscription that launches following seeded error workflow process.
  • Workflow Type - WFERROR
  • Workflow Process - DEFAULT_EVENT_ERROR
If an error subscription is not created event subscription failures may go unnoticed. Create the error subscription as follows.
Subscription2.jpg
Subscription2Details.jpg

Sample Local Subscription

For testing purposes, let us assume following PLSQL rule function (in package XXX_PACKAGE) used in a LOCAL event subscription with phase > 99. This will cause the event to be enqueued to WF_DEFERRED queue and Workflow Agent Listener process to execute it in the background. This function inserts records into a temporary table.
    create table temp_table (key_value varchar2(50), result varchar2(20));
    create or replace package xxx_package is
      function subscription1 (p_subscription_guid in raw,
                              p_event in out nocopy wf_event_t) return varchar2;
    end xxx_package;
    /
    create or replace package body xxx_package is
      function subscription1(p_subscription_guid in raw,
                           p_event in out nocopy wf_event_t) return varchar2 is
        l_result varchar2(20);   
      begin
        --processing...
        l_result := p_event.GetValueForParameter('OUTCOME');
        if l_result='GOOD' then
          insert into temp_table values (p_event.getEventKey(), l_result);
          return 'SUCCESS';
        else
          insert into temp_table values (p_event.getEventKey(), l_result);
          wf_core.context('xxx_package','function subscription1', p_event.getEventName(), p_event.getEventKey());
          wf_event.setErrorInfo(p_event, 'ERROR');
          return 'ERROR';
        end if;
      exception
        when others then
          wf_core.context('xxx_package','function subscription1', p_event.getEventName(), p_event.getEventKey());
          wf_event.setErrorInfo(p_event, 'ERROR');
          return 'ERROR';
      end subscription1;
    end xxx_package;
    /
IMPORTANT NOTE: Return value should be in UPPERCASE, otherwise the Business Event System will not recognize the result.

Test the business event

Write a PLSQL procedure to create and set the event parameters and then raise it. 
     declare
      l_event_name varchar2(50) := 'oracle.apps.fnd.wfds.user.userUpdated';
      l_event_key varchar2(50) := to_char(sysdate, 'DD-MM-RRRR HH:MI:SS');
      l_attributes wf_parameter_list_t;
    begin
      --Add the logic to be executed when the event occurs. In this case the
      -- creation of a user was signaled.
      -- ...
      --Add all the parameters to the list:
      --WF_EVENT.AddParameterToList('OUTCOME', 'WRONG', l_attributes);
      WF_EVENT.AddParameterToList('OUTCOME', 'GOOD', l_attributes);
      -- Raise the event
      WF_EVENT.Raise(p_event_name => l_event_name,
                     p_event_key => l_event_key,
                     p_parameters => l_attributes);
      commit;
    end;
    /
When this block runs with parameter OUTCOME set to 'GOOD', a record is inserted into TEMP_TABLE by the LOCAL subscription's rule function. When a different value is used the function returns ERROR and a record is insert into the temporary table. But since the result is ERROR, the transaction is rolled back and error subscription is executed. The Business Event System uses the error subscription to launch WFERROR:DEFAULT_EVENT_ERROR process to send error notification to SYSADMIN with the details of the exception. These error details shown on the notification are as a result of the calls to WF_EVENT.SetErrorInfo and WF_CORE.Context in the subscription rule function.
SysadminNotification.jpg

Troubleshooting Tips

  • Only Busienss Events with asynchronous subscriptions are enqueued to WF_DEFERRED or WF_JAVA_DeFERRED queues based on whether the subscription is PLSQL based or Java based. All events with synchronous subscriptions are executed in the same thread they are raised in and not enqueued to any AQs.
    NOTE: The event's synchronous subscriptions themselves may enqueue the events to some Out Agents such as WF_JMS_OUT or WF_WS_JMS_OUT and so on which is purely specific to subscription's implementation and not related to core Business Event processing.
  • From Workflow Manager, ensure the Workflow Deferred Agent Listener and the Workflow Java Deferred Agent Listener components are running
  • Ensure an ERROR subscription is created for the business event
  • To trace a business event with Asynchronous Subscription from Raise to Dispatch to Error
    • Ensure an error subscription was created as in the sample above
    • Stop Workflow Deferred Agent Listener and Workflow Error Agent Listener
    • Raise the event
    • Verify the event is enqueued to WF_DEFERRED using below SQL. Assuming the event key is unique across all occurences, it should return 1
      select count(1) from applsys.aq$wf_deferred a where a.user_data.event_name = '&eventName'and a.user_data.event_key = '&eventKey' and a.msg_state = 'READY';
    • Start Workflow Deferred Agent Listener and after few minutes verify the event is processed successfully using above SQL. The count should be 0
    • If the event was not dispatched successfully, check if the event is enqueued to WF_ERROR queue using SQL. If the event errored, it should be in error queue. If this SQL returns 0, the subscription was executed successfully. select count(1) from applsys.aq$wf_error a where a.user_data.event_name = '&eventName'and a.user_data.event_key = '&eventkey'and a.msg_state = 'READY'
    • Start Workflow Error Agent Listener. If there was a record in WF_ERROR queue, after few minutes verify the event is processed successfully using above SQL
    • Now check SYSADMIN's worklist for error notification with details of the error.
  • To obtain E-Business Debug Log messages for business event processing
    • Enable Log profile options for the E-Business Suite user whose session triggers the business event.
      FND: Debug Log Enabled=YES
      FND: Debug Log Level=STATEMENT
      FND: Debug Log Module=wf.plsql%
    • In the case where the event is raised from a PLSQL block you can add the following at begining of the procedure to identify the session and to activate the debug profile options.
      declare

      ...

      begin

        fnd_global.apps_initialize(user_id=>0, resp_id=>24240, resp_appl_id=>1);

        --...

      end;

      fnd_global.apps_initialize will enable the profile options for this PLSQL block for user SYSADMIN, application 'System Administration' and responsibility 'System Administrator'
    • Then query table APPLSYS.FND_LOG_MESSAGES where column MODULE like 'wf.plsql%' to see the debug messages
      sqlplus apps/***** @$FND_TOP/patch/115/sql/wfdbgprnt wf.plsql%

References

Oracle Workflow API Reference, section 'Event Subscription Rule Function APIs'
Oracle Workflow Developer's Guide, section 'Error Handling for Event Subscription Processing'
Reference Form : Oracle Blogs

Business event does not raise - event raises and does nothing

Business event does not raise - event raises and does nothing

Frequently, new functionality is created using the Business Event System or existing functionality is changed by adding new subscriptions, changing subscription phases, changing underlying java or PLSQL code, etc, and inexplicably it is found that raising the business event does not produce the desired result, as if the event was not raised.
The execution of an event consists basically of two parts: raising the event and do all required validation, and then finding the subscriptions to that event and execute them. The first one barely ever fails while the second one is more pron to issues and it is the one that we are mostly interested in as it has the code/behavior we want to see.
The following steps will allow to identify the actual cause of the issue by making use of the FND debugging options provided in EBS.

1. Adjust the subscription phase

Since subscriptions with phase higher than 100 are deferred you would need to raise the event on one session and then go to another session and debug it. It is easier if you can set the phase to a value lower than 100, say 99, and then raise the event in the session. This way you will be able to see everything the happens related to this event subscription, a nothing else.
Remember to ensure that the business event has an error subscription so that if something happens it does not go silent. By adding an ERROR subscription the system administrator would be able to see as notification explaining any failures. See here for more on error subscription definitions. 

2. Raise the event 

Do so either from the application or from java or PLSQL. Here is an example from PLSQL.
Note: you can make use of wf_log_pkg.init to enable the FND: Debug option for this session only, so there is no need to change the corresponding profile options. The last parameter ('wf%') means the debug is enabled for the WF code, which the BES belongs to.
declare
  l_parameters wf_parameter_list_t := wf_parameter_list_t();
begin
  --Optional:
  --execute immediate 'truncate table applsys.fnd_log_messages';
  --Add your parameters here
  wf_log_pkg.init(1, null, 1, 'wf%');
  wf_event.addparametertolist(p_name          => 'NOTIFICATION_ID',
                              p_value         => '123',
                              p_parameterlist => l_parameters);
  wf_event.raise(p_event_name => 'oracle.apps.wf.notification.send',
                 p_event_key  => '123',
                 p_event_data => NULL,
                 p_parameters => l_parameters,
                 p_send_date  => sysdate);
  commit;
end;
/
anonymous block completed 

3. Find the logging details 

Now, within the same session check the log messages generated by the Business Event System:
SELECT 'Level: '||log_level||
       ' Module: '||module||
       ' Time: '||to_char(timestamp, 'DD-MON-RR HH24:MI:SS')||
       wf_core.newline||
       '>>> Message: '||message_text
FROM   fnd_log_messages
WHERE  audsid  =  sys_context('userenv', 'SESSIONID')
ORDER BY log_sequence
/ 
 
The final lines found in the query above and the error notifications sent to the system administrator will point out to the error causing the event to look as it did not fire.

Reference : Oracle Blogs