Publishing from Server Script
- OK when the Kafka publish succeeds.
- NOTOK when the Kafka publish fails.
You can update server scripts to capture this result and implement custom error handling. This section lists simplified examples to demonstrate how to send event data to Kafka using a server script and handle errors.
You use the setProperty method to publish a topic to specific Kafka
partitions. The following example is a section of the server script that demonstrates
how to publish event data to specific partitions:
function Service_PreInvokeMethod (MethodName, Inputs, Outputs)
{
var nReturn = ContinueOperation;
var oBS;
var ch1;
var outPS;
var conPS;
var accPS;
switch (MethodName)
{
case "PublishContact"
ch1 = TheApplication().NewPropertySet();
outPS = TheApplication().NewPropertySet();
conPS = TheApplication().NewPropertySet();
accPS = TheApplication().NewPropertySet();
accPS.SetProperty("topic","AccountData");
accPS.SetProperty("partitions", "0,1,3");
ch1.SetType("Contact");
ch1.SetProperty("First Name", "Anil");
ch1.SetProperty("Last Name", "Kumar");
conPS.AddChild(ch1);
conPS.SetProperty("Account Name","SF");
conPS.SetType("Account");
accPS.AddChild(conPS);
oBS = TheApplication().GetService("Event Handler");
oBS.InvokeMethod("SendEvent", accPS, outPS);
nReturn = CancelOperation;
break;
}
return nReturn;
}
In the example above, the Partitions property for AccountData is set to the values 0, 1, and 3. Hence, the JSON message generated for AccountData using this server script will be posted to these partitions.
The following example demonstrates how a JSON payload is posted to Kafka based on the
value of the SingleRecordAsJSONObject property:
function Service_PreInvokeMethod (MethodName, Inputs, Outputs)
{
var nReturn = CancelOperation;
var oBS;
var topPS;
var outPS;
var conPS;
var accPS;
var fieldList = ["First Name", "Last Name"];
switch (MethodName) {
case "PublishContact":
topPS = TheApplication().NewPropertySet();
outPS = TheApplication().NewPropertySet();
conPS = TheApplication().NewPropertySet();
accPS = TheApplication().NewPropertySet();
topPS.SetProperty("topic","customcontactevent");
accPS.SetType("Account");
accPS.SetProperty("Name",”NoAccount123");
accPS.SetProperty("SingleRecordAsJSONObject",”true");
conPS.SetType("Contact");
for (var j=0; j<fieldList.length; j++)
{
conPS.SetProperty(fieldList[j], "NoName");
}
accPS.AddChild(conPS);
topPS.AddChild(accPS);
oBS = TheApplication().GetService("Event Handler");
oBS.InvokeMethod("SendEvent", topPS, outPS);
break;
}
return nReturn;
}
}
Based on the configuration in the above example and assuming that
SIEBEL_EVENT_PUBSUB_PAYLOAD_STRUCT is set to 2,
the business objects are posted as follows:
{
"Account": {
"Name": "NoAccount123",
"Contact": [
{
"First Name": "NoName",
"Last Name": "NoName"
}
]
}
}
- A single data record of “Contact” will be posted as an array as the
SingleRecordAsJSONObjectproperty is not set. - A single data record of “Account” will be posted as a JSON object as the
SingleRecordAsJSONObjectproperty is set totrue.
The following example shows how to handle an exception and display an appropriate error message:
function Service_PreInvokeMethod (MethodName, Inputs, Outputs)
{
var nReturn = CancelOperation;
var oBS;
var inpPS;
var outPS;
var conPS;
var qtPS;
var accPS;
var inpPS1;
var fieldList = ["First Name", "Last Name"];
switch (MethodName) {
case "PublishContact":
try{
inpPS = TheApplication().NewPropertySet();
inpPS1 = TheApplication().NewPropertySet();
outPS = TheApplication().NewPropertySet();
conPS = TheApplication().NewPropertySet();
qtPS = TheApplication().NewPropertySet();
accPS = TheApplication().NewPropertySet();
accPS.SetProperty("topic","customcontactevent");
accPS.SetProperty("Partitions", "0,1,2,3");
for (var j=0; j<fieldList.length; j++) {
inpPS.SetProperty(fieldList[j], "NoName");
}
for (var k=0; k<fieldList.length; k++) {
inpPS1.SetProperty(fieldList[k], "NoNameEver");
}
inpPS1.SetProperty("SingleRecordAsJSONObject","true");
qtPS.SetProperty("QuoteName","NoQtName");
qtPS.SetProperty("SingleRecordAsJSONObject","true");
qtPS.SetType("Quote");
inpPS.SetType("Contact");
inpPS.AddChild(qtPS);
conPS.AddChild(inpPS);
inpPS1.SetType("Contact");
conPS.AddChild(inpPS1);
conPS.SetProperty("Name","NoAccount123");
conPS.SetProperty("SingleRecordAsJSONObject","true");
conPS.SetType("Account");
accPS.AddChild(conPS);
oBS = TheApplication().GetService("Event Handler");
oBS.InvokeMethod("SendEvent", accPS, outPS);
}
catch (e)
{
var errMsg = "SendEvent failed. Code=" + e.errCode + ", Text=" + e.errText;
TheApplication().Trace(errMsg);
}
break;
}
return nReturn;
}
The script publishes a payload to the Kafka topic customcontactevent. If
Kafka is unavailable, the behavior is as follows:
- If the Kafka server is unavailable, the message is lost and no retry attempts are
performed. In this scenario, the Siebel server receives a
NOTOKresponse. - If the Kafka bróker or the sidecar AI service is unavailable, the operation throws
an exception. The exception can be handled in the
catchblock to display the error message. You can also modify the script to implement custom error-handling logic and prevent data loss, such as logging the payload when a failure occurs.
The following example shows how to implement custom error-handling logic in case of failure:
function Service_PreInvokeMethod (MethodName, Inputs, Outputs)
{
var nReturn = CancelOperation;
var oBS;
var inpPS;
var outPS;
var childPS;
var childPS12;
var gChildPS;
try
{
switch (MethodName)
{
case "ProcessEvent":
inpPS = TheApplication().NewPropertySet();
childPS = TheApplication().NewPropertySet();
childPS12 = TheApplication().NewPropertySet();
gChildPS = TheApplication().NewPropertySet();
inpPS.SetProperty("name", "abc");
inpPS.SetType("Color");
gChildPS.SetProperty("altName","abcd");
gChildPS.SetProperty("eid",254);
childPS.SetProperty("age", "25");
childPS.SetProperty("location", "Mumbai");
childPS.SetType("ChildLocation");
childPS12.SetProperty("age", "35");
childPS12.SetProperty("location", "Bengaluru");
childPS12.SetType("ChildLocation2");
childPS12.AddChild(gChildPS);
inpPS.AddChild(childPS);
inpPS.AddChild(childPS12);
outPS = TheApplication().NewPropertySet();
inpPS.SetProperty("topic", "externalcrmevent");
oBS = TheApplication().GetService("Event Handler");
oBS.InvokeMethod("SendEvent", inpPS, outPS);
break;
}
}
catch (e)
{
var fp = null;
var fileName = "ProcessEventPSDump.txt";
var logMsg = PrintPSDataAsLog(inpPS, "", "");
fp = Clib.fopen(fileName, "w");
if (fp == null)
{
TheApplication().RaiseErrorText("Unable to open file: " + fileName);
}
Clib.fputs(logMsg, fp);
Clib.fclose(fp);
fp = null;
Outputs.SetProperty("PropertySetDump", logMsg);
}
return nReturn;
}
The following example shows the PrintPSDataAsLog function that is called by the preceding server script:
function PrintPSDataAsLog(ps, strLogMsg, Indentation)
{
var prop;
var propValue;
var strPSType;
var pChildPS;
var nChildCount;
var index;
var depth;
var isRoot;
var MAX_DEPTH = 25;
var MAX_LOG_CHARS = 100000;
var MAX_VALUE_CHARS = 2000;
if (strLogMsg == null)
strLogMsg = "";
if (Indentation == null)
Indentation = "";
isRoot = (Indentation == "");
if (ps == null)
return strLogMsg + "\n" + Indentation + "<null property set>";
if (strLogMsg.length > MAX_LOG_CHARS)
return strLogMsg + "\n" + Indentation + "<log truncated>";
depth = Indentation.length / 2;
if (depth > MAX_DEPTH)
return strLogMsg + "\n" + Indentation + "<max depth reached>";
strPSType = ps.GetType();
if (strPSType == null || strPSType == "")
strPSType = "PropertySet";
nChildCount = ps.GetChildCount();
if (!isRoot)
strLogMsg += "\n";
strLogMsg += Indentation + "Entity: " + strPSType;
Indentation += " ";
prop = ps.GetFirstProperty();
while (prop != null && prop != "")
{
propValue = ps.GetProperty(prop);
if (propValue == null)
propValue = "";
propValue = "" + propValue;
propValue = propValue.split("\\").join("\\\\");
propValue = propValue.split("\r").join("\\r");
propValue = propValue.split("\n").join("\\n");
if (propValue.length > MAX_VALUE_CHARS)
propValue = propValue.substring(0, MAX_VALUE_CHARS) + "<truncated>";
strLogMsg += "\n" + Indentation + prop + " = " + propValue;
if (strLogMsg.length > MAX_LOG_CHARS)
return strLogMsg + "\n" + Indentation + "<log truncated>";
prop = ps.GetNextProperty();
}
for (index = 0; index < nChildCount; index++)
{
pChildPS = ps.GetChild(index);
strLogMsg += "\n" + Indentation + "ChildEntity:";
strLogMsg = PrintPSDataAsLog(pChildPS, strLogMsg, Indentation + " ");
if (strLogMsg.length > MAX_LOG_CHARS)
return strLogMsg + "\n" + Indentation + "<log truncated>";
}
if (isRoot)
{
while (strLogMsg.length > 0 &&
(strLogMsg.charAt(strLogMsg.length - 1) == "\n" ||
strLogMsg.charAt(strLogMsg.length - 1) == "\r" ||
strLogMsg.charAt(strLogMsg.length - 1) == " "))
{
strLogMsg = strLogMsg.substring(0, strLogMsg.length - 1);
}
}
return strLogMsg;
}
If a failure occurs, the preceding server script writes the following response to the file:
Entity: Color
topic = externalcrmevent
name = abc
ChildEntity:
Entity: ChildLocation
location = Mumbai
age = 25
ChildEntity:
Entity: ChildLocation2
location = Bengaluru
age = 35
ChildEntity:
Entity: PropertySet
eid = 254
altName = abcd