%SYS.Task.Definition to kick off Ens.BusinessService using EnsLib.SQL.InboundAdapter
How can I create a Task that tells a Ens.BusinessService to execute its SQL query using the EnsLib.SQL.InboundAdapter?
So far I have come up with
Class OSU.Workday.TerminationsTask Extends %SYS.Task.Definition
{
Parameter TaskName As STRING = "OSU - Workday Termination Update";
Method OnTask() As %Status
{
try{
// Call BusinessService
set tSC = ##class(Ens.Director).CreateBusinessService("OSU.DataSource.Workday.TermService",.tService)
if $IsObject(tService){
set inputMessage = ##class(Ens.StringContainer).%New()
set inputMessage.StringValue = "1"
Set tSC = tService.ProcessInput(inputMessage,.output)
} Else {
Set tSC = $$$ERROR($System.Status.GetErrorCodes(tSC), "Failed to create Business Service")
}
}catch ex{
set tSC = ex.AsStatus()
}
quit tSC
}
/// Location and Revision of this file in Perforce (Auto-updating)
Parameter SrcVer = "$Id: //custom_ccrs/us/OSUM/OSUMHSCUSTOM/UAT/cls/OSU/Workday/TerminationsTask.xml#20 $";
}
and
Class OSU.Workday.TerminationService Extends Ens.BusinessService
{
Parameter ADAPTER = "EnsLib.SQL.InboundAdapter";
Method OnProcessInput(pInput As EnsLib.SQL.Snapshot, pOutput As %RegisteredObject) As %Status
{
set req = ##class(OSU.Workday.Messages.WorkdayTerminations).%New()
set req.EMPLID = pInput.Get("EMPLID")
set req.MedCtrID = pInput.Get("MedCtrID")
set req.LastName = pInput.Get("LastName")
set req.FirstName = pInput.Get("FirstName")
set req.EFFDT = pInput.Get("EFFDT")
set req.MiddleName = pInput.Get("MiddleName")
set req.Gender = pInput.Get("Gender")
set req.DOB = pInput.Get("DOB")
set req.NPI = pInput.Get("NPI")
set req.DoctorNumber = pInput.Get("DoctorNumber")
set req.VerityID = pInput.Get("VerityID")
set req.SSN = pInput.Get("SSN")
set req.IDMID = pInput.Get("IDMID")
set sc = ..SendRequestSync("OSU.DataSource.Workday.Term.Process", req)
quit sc
}
/// Location and Revision of this file in Perforce (Auto-updating)
Parameter SrcVer = "$Id: //custom_ccrs/us/OSUM/OSUMHSCUSTOM/UAT/cls/OSU/Workday/TerminationService.xml#4 $";
}I am trying to use the Task to schedule the query to run once a Day from the Task Scheduler and not using the Schedule from within the Namespace. However, when I try to use the Task and Service, the Service is expecting EnsLib.SQL.Snapshot to be passed on the ProcessInput. But I want the Business Service to execute the Query defined within the settings and not have to rely on the Task to execute the external SQL Query via JDBC. I know I am missing something somewhere. Can someone give me some guidance?
Comments
To create a task that triggers the execution of a Ens.BusinessService using the EnsLib.SQL.InboundAdapter, the general approach involves:
- Task Definition: Using
%SYS.Task.Definitionto define task logic. - Business Service: Ensure proper configuration of the business service to use the SQL adapter.
- Trigger Mechanism: Integrating the task and service for seamless execution.
Task Implementation:
Here’s an example approach that can address your specific use case:
- Extend
%SYS.Task.Definitionfor custom task logic. - Use the
OnTask()method to instantiate and invoke the business service.
Class Sample.Task.TriggerSQLServiceTask Extends %SYS.Task.Definition
{
/// The name of the Business Service to be executed
Property BusinessServiceName As %String [Required];
Method OnTask() As %Status
{
// Create BusinessService object
#dim businessServiceInstance As Ens.BusinessService
set tSC = ##class(Ens.Director).CreateBusinessService(..BusinessServiceName, .businessServiceInstance)
$$$ThrowOnError(tSC)
// Invoke the service's OnTask or similar method
quit businessServiceInstance.OnTask()
}
}
You define a BusinessServiceName property in the task class, which indicates the service to be triggered. When the task is executed, this task will dynamically create and execute the specified business service.
Scheduling the Task:
The service can be linked with the system’s task scheduler by defining the task scheduling parameters. The parameters will allow daily or specific-time execution of the query.
Key Considerations for Your Business Service:
-
Configure the
EnsLib.SQL.InboundAdapterto specify the SQL query and other relevant settings (e.g., DSN or database connectivity details). -
Use the
OnProcessInput()method in the service to handle any incoming snapshots or inputs from the SQL query results. For example:Method OnProcessInput(pInput As EnsLib.SQL.Snapshot, pOutput As %RegisteredObject) As %Status { set req = ##class(OSU.Workday.Messages.WorkdayTerminations).%New() set req.EMPLID = pInput.Get("EMPLID") // Add additional field mappings ... quit ..SendRequestSync("TargetConfigName", req) }
Other Options:
If you do not want to handle SQL execution directly in the task but let the Business Service control it:
- Ensure the service is appropriately configured to handle its SQL logic independently.
- The task simply activates the service for its execution, relying on the internal adapter setup for query execution.
For more tailored implementation details, please refer to the examples provided in the source where tasks and services interact:
- Custom SQL adapters and Business Service connections 1.
- Methods for defining task-triggered services 21.
Sources:
For polling adapters such as EnsLib.SQL.InboundAdapter, calling the adapter's OnTask() method should trigger one run. Something like
ClassMethod CallServiceAdapter(targetConfigName As Ens.DataType.ConfigName) As %Status
{
#Dim sc as %Status
#Dim ex as %Exception.AbstractException
#Dim service as Ens.BusinessService
s sc = $$$OK
try {
$$$TOE(sc,##class(Ens.Director).CreateBusinessService(targetConfigName,.service))
$$$TOE(sc,service.Adapter.OnTask())
}
catch (ex) {
s sc = ex.AsStatus()
}
return sc
}Would I have to define a OnTask within the Business Service, or is that built in?
Hi @Scott Roth
The OnTask is a built in method of EnsLib.SQL.InboundAdapter that execute the query and call ProcessInput method from Business Service passing a EnsLib.SQL.Snapshot to be processed.
Yes. In addition, to prevent the default Ens.BusinessService behavior to call adapter OnTask() every CallInterval seconds, you can override the OnTask() method of the business service.
And while we are at it 😁 add a TriggerService() class method, and use it in the scheduled task to trigger the service adapter just once :
Class dc.sql.TriggeredSQLService Extends EnsLib.SQL.Service.GenericService
{
Method OnTask() As %Status
{
// do nothing
}
Method Trigger() As %Status
{
return ..Adapter.OnTask()
}
ClassMethod TriggerService(configName As Ens.DataType.ConfigName) As %Status
{
#Dim sc as %Status
#Dim ex as %Exception.AbstractException
#Dim service as Ens.BusinessService
s sc = $$$OK
try {
$$$TOE(sc,##class(Ens.Director).CreateBusinessService(configName,.service))
if service.%Extends($classname()) {
$$$TOE(sc,service.Trigger())
}
}
catch (ex) {
s sc = ex.AsStatus()
}
return sc
}
}
Use schedules or if you need just close enough you can do this:
- Check how much time, on average BS takes to run. Let's say X seconds.
- Set Call Interval on your BS to 86400-X.
- Start BS at 10:00 AM.
- Assuming the average runtime stays constant, it should work well enough.