Snippets marked with * are mandatory and should be used in messaging enabled processes.
Declaration Snippet*
Following code needs to be added into suitable part of prolog, ideally to variables declaration part. The snippet defines variables that are used to communicate results of the process to its caller.
Note: You should make sure you are using Apliqo template empty process as some of variables defined there are used in the messaging solution as well. These are following:
sProcLogParams
cUserName
cThisProcName
Code Block |
---|
### Global Variables
StringGlobalVariable('sProcessReturnCode');
NumericGlobalVariable('nProcessReturnCode');
nProcessReturnCode= 0;
cMsgErrorLevel = 'ERROR';
cMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';
# Uncomment for thread enabled processes
#cMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% (ThreadID: %pThreadID%) ErrorMsg:%sMessage%';
nErrors = 0;
sMessage = '';
cCubMsg = '}APQ Process Response Message';
sMultiMsg = '';
nMultiMsgJSON = 0;
sDetailMsg = '';
nSubProcessNumber = 0; |
License Test Snippet*
This snippet should be added to a first line of code after declarations to check license validity.
Code Block |
---|
If( CellGetN( cCubParam, 'Customer Name', 'Numeric' ) + CellGetN( cCubParam, 'Customer Key', 'Numeric' ) < 2 );
nErrors = nErrors + 1;
sMessage = 'Product license is not valid, please set customer key in }APQ Settings!';
sSequenceID = NumberToString( nMultiMsgJSON );
sMessageJSON = INSRT(' "message":"', sMessage | '"', 1);
sMultiMsg = Expand( '%sMultiMsg%' | If(LONG(sMultiMsg)=0, '', ', ') | '"' | NumberToString( nMultiMsgJSON ) | '":{%sMessageJSON%}' ); nMultiMsgJSON = nMultiMsgJSON + 1;
LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );
ProcessBreak;
EndIf; |
Parameter Value Error Snippet
This snippet is used when an error is identified, typically when checking if supplied parameters are valid. You may use ProcessBreak to stop code execution immediately or you may proceed with error checking and stack all eventual error messages.
Code Block |
---|
IF( pVersion @= '' );
nErrors = nErrors + 1;
sMessage = 'Parameter pVersion must not be empty.';
sSequenceID = NumberToString( nMultiMsgJSON );
sMessageJSON = INSRT(' "message":"', sMessage | '"', 1);
sMultiMsg = Expand( '%sMultiMsg%' | If(LONG(sMultiMsg)=0, '', ', ') | '"' | NumberToString( nMultiMsgJSON ) | '":{%sMessageJSON%}' ); nMultiMsgJSON = nMultiMsgJSON + 1;
LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );
ProcessBreak;
EndIf; |
Info Snippet
This snippet might be used to add useful information about the process execution - for instance information about parameter values being used.
Code Block |
---|
sMessage = 'Data processing start.';
sSequenceID = NumberToString( nMultiMsgJSON );
sMessageJSON = INSRT(' "message":"', sMessage | '"', 1);
sMultiMsg = Expand( '%sMultiMsg%' | If(LONG(sMultiMsg)=0, '', ', ') | '"' | NumberToString( nMultiMsgJSON ) | '":{%sMessageJSON%}' ); nMultiMsgJSON = nMultiMsgJSON + 1;
LogOutput( 'Info', sMessage ); |
Subprocess (without messaging) Error Detection
This snippet is used when calling a subprocesses that are not enabled with messaging to indicate if an error occurred during execution.
Code Block |
---|
sProc = 'process';
nRet = ExecuteProcess( sProc );
IF( nRet <> ProcessExitNormal );
nErrors = nErrors + 1;
sRet = NumberToString( nRet );
sMessage = Expand( 'Call to %sProc% has finished with errors (code = %sRet%).' );
sSequenceID = NumberToString( nMultiMsgJSON );
sMessageJSON = INSRT(' "message":"', sMessage | '"', 1);
sMultiMsg = Expand( '%sMultiMsg%' | If(LONG(sMultiMsg)=0, '', ', ') | '"' | NumberToString( nMultiMsgJSON ) | '":{%sMessageJSON%}' ); nMultiMsgJSON = nMultiMsgJSON + 1;
LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );
ProcessBreak;
EndIF; |
Subprocess (with messaging) Error Detection and Message Passing
This snippet might be used when calling a subprocess equipped with messaging to get messages from the called subprocess and pass them to JSON string of the calling process.
Code Block |
---|
sProc = 'Process';
nRet = ExecuteProcess( sProc );
nSubProcessNumber = nSubProcessNumber + 1;
sMessage = INSRT('"sequence":"' | NumberToString( nSubProcessNumber ) | '", ', sProcessReturnCode, 2);
sMessageJSON = INSRT(' "message":', sMessage, 1);
sMultiMsg = Expand( '%sMultiMsg%' | If(LONG(sMultiMsg)=0, '', ', ') | '"' | NumberToString( nMultiMsgJSON ) | '":{%sMessageJSON%}' ); nMultiMsgJSON = nMultiMsgJSON + 1;
IF( nRet <> ProcessExitNormal % nProcessReturnCode = 0 );
nErrors = nErrors + 1;
sRet = NumberToString( nRet );
sMessage = Expand( 'Call to %sProc% has finished with errors (code = %sRet%).' );
sMessageJSON = INSRT(' "message":"', sMessage | '"', 1);
sMultiMsg = Expand( '%sMultiMsg%' | If(LONG(sMultiMsg)=0, '', ', ') | '"' | NumberToString( nMultiMsgJSON ) | '":{%sMessageJSON%}' ); nMultiMsgJSON = nMultiMsgJSON + 1;
LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );
ProcessBreak;
EndIF; |
Final Message Preparation for Process without Parallelism*
This snippet should be put into epilog of the messaging enabled process to make sure the final message is properly formulated as a JSON string and global variables to pass messages to a calling process are set. The snippet is valid only for processes that are not parallel enabled and run in single thread mode and should be last code block in epilog tab of the process.
Note:
Messages are written into message cube by calling a process with
RunProcess
to isolate commit event of the message from commit event of the process. This might result in some time differences between the time when message is actually written and process result is indicated and the actual process finish.nProcessReturn
code is by definition set to 0 in case of process errors and non-zero otherwise!
Code Block |
---|
#Region - Return code & final error message handling
sProcessResultType = If( nErrors = 0, 'success', 'danger' );
If( nErrors > 0 );
sErrors = NumberToString( nErrors );
#Region - Failure Message Composition
sProcessResultMsg = Expand( 'Process has finished with %sErrors% error' | If( nErrors > 1, 's', '') | '.' );
#EndRegion - Failure Message Composition
If( nMultiMsgJSON <= 1 );
sProcessResultJSON = Expand( '{"process":"%cThisProcName%", "header": "%sProcessResultMsg%", "message":"%sMessage%", "type":"%sProcessResultType%"}' );
Else;
sProcessResultJSON = Expand( '{"process":"%cThisProcName%", "header": "%sProcessResultMsg%", "details":{%sMultiMsg%}, "type":"%sProcessResultType%"}' );
EndIf;
sMessage = sProcessResultMsg;
nProcessReturnCode = 0;
sProcessReturnCode = sProcessResultJSON;
RunProcess( '}APQ.Cub.ProcessResponseMessage.ImmediateLog',
'pProcLogParams', sProcLogParams,
'pProcessStartTime', TimSt(nProcessStartTime, '\Y-\m-\d \h:\i:\s'),
'pProcessFinishTime', 'now',
'pUserName', cUserName,
'pProcessName', cThisProcName,
'pProcessErrorFile', GetProcessErrorFileName(),
'pStatus', 'Error',
'pSuccessMessage', '',
'pFailureMessage', sProcessResultMsg,
'pJSONMessage', sProcessReturnCode
);
LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );
ProcessQuit();
Else;
#Region - Success Message Composition
sProcessResultMsg = 'Process has finished successfully.';
#EndRegion - Success Message Composition
If( nMultiMsgJSON <= 1 );
sProcessResultJSON = Expand( '{"process":"%cThisProcName%", "header": "%sProcessResultMsg%", "message":"%sMessage%", "type":"%sProcessResultType%"}' );
Else;
sProcessResultJSON = Expand( '{"process":"%cThisProcName%", "header": "%sProcessResultMsg%", "message":"%sMessage%", "details":{%sMultiMsg%}, "type":"%sProcessResultType%"}' );
EndIf;
nProcessReturnCode = 1;
sProcessReturnCode = sProcessResultJSON;
RunProcess( '}APQ.Cub.ProcessResponseMessage.ImmediateLog',
'pProcLogParams', sProcLogParams,
'pProcessStartTime', TimSt(nProcessStartTime, '\Y-\m-\d \h:\i:\s'),
'pProcessFinishTime', 'now',
'pUserName', cUserName,
'pProcessName', cThisProcName,
'pProcessErrorFile', GetProcessErrorFileName(),
'pStatus', 'Success',
'pSuccessMessage', sProcessResultMsg,
'pFailureMessage', '',
'pJSONMessage', sProcessReturnCode
);
LogOutput('INFO', Expand( 'Process:%cThisProcName%: %sMessage%' ) );
EndIf;
#EndRegion - Return code & final error message handling |
Final Message with Record Count and Time Stats
You should use this snippet when you want to indicate process run time and volume of data it has processes. In order to use this snippet you should replace region Success Message Composition
in the epilog in above snippet. You will have to declare variables to store number of records processed (either in Metadata or Data - depends on logic of your process) in Prolog in order to use this snippet and increment the record counter each time a record is successfully processed in respective tab.
Prolog
Code Block |
---|
nDataRecordCount = 0; |
Data
Code Block |
---|
nDataRecordCount = nDataRecordCount + 1; |
Epilog
Code Block |
---|
#Region - Success Message Composition
nTime = NOW();
nDeltaTime = ROUND( (nTime - nTimeStart) * 3600 * 24 );
sDeltaTime = NumberToString( nDeltaTime );
sRateAVG = NumberToString( nDataRecordCount \ nDeltaTime );
sDataRecordCount = NumberToString(nDataRecordCount);
If( nDataRecordCount = 0 );
sMessage = Expand( 'No records were processed!' );
sProcessResultMsg = Expand( 'Process has finished without errors.' );
Else;
sMessage = Expand( 'Successfully processed %sDataRecordCount% records in %sDeltaTime% s. Average throughput=%sRateAVG% records/s.' );
sProcessResultMsg = Expand( 'Process has finished successfully.' );
EndIf;
#EndRegion - Success Message Composition |