Get status of a job

User5099 (22 posts)
April 28, 2017 11:23 AM
Accepted Answer

Hi Bill,

It would be great if you could please provide me examples on how to get status of job in adTempus 3.0. I am successfully able to get the job name. Now for that job I want to  get details like status of job and so on.

Working Environment: Visual Studio 2017, adTempus 3.0, C# language

Bill Staff (601 posts)
April 28, 2017 11:52 AM
Accepted Answer
Once you have the job, use GetStatus to get the status object, or use GetExecutionHistory if you need to look at recent instances of the job.
User5099 (22 posts)
April 28, 2017 11:59 AM
Accepted Answer

Hi Bill,

Thanks for such a quick reply. I am returning an ADTObject, could you please let me know how do I convert this to ExecutionHistoryItem Object or  Job Object so that I can access the properties and methods of these object.

PLease find the code below for reference

public static IADTObjects GetJobsForName(IScheduler connection, string jobName) {      JobByNameFilter filter = new JobByNameFilter(jobName);    

 Int32 recordCount = default(Int32);     filter.singleGroupOnly = false;   

   return connection.GetObjectsWhere(filter, 0, true, out recordCount);

}

Bill Staff (601 posts)
April 28, 2017 12:09 PM
Accepted Answer

Take a look at the Getting a job by name example in the documentation. You'll want to recreate the JobGetter class in C# and use it to fetch the job by name. It handles casting the returned object to Job. In C# you just do a direct cast to the IJob interface:

(IJob)obj

or

obj as IJob

You can use the CID property of an ADTObject to find out what kind it is if you need to, but once you get past the GetObjects methods, most properties and methods are strongly-typed and will return the correct interface.

Note that all of this discussion only applies to the v3 API; in V4 there are much better methods for fetching objects, and they're strongly-typed.

User5099 (22 posts)
April 28, 2017 12:14 PM
Accepted Answer
Thanks a lot Bill.
User5099 (22 posts)
April 28, 2017 12:30 PM
Accepted Answer

Hi Bill,

When I try to do Explicit Type casting I get the below error

"System.InvalidCastException: 'Unable to cast COM object of type 'System.__ComObject' to interface type 'ArcanaDevelopment.adTempus.Client.Job'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{348EB495-F0FA-45B7-A9DE-9D14E76D9AAE}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).'" . could you please let me kniw, if its related to installation issues?

Bill Staff (601 posts)
April 28, 2017 01:15 PM
Accepted Answer

It's not related to installation issues.

Please post your code. What's the CID for the object you're trying to cast?

User5099 (22 posts)
April 28, 2017 01:38 PM
Accepted Answer

Hi Bill,

Please find my code below

public List<String> getPortfolioNames() {     

List<String> jobs = null;           

        Application app = new Application();         

Scheduler sched = app.ConnectRemote("", "", "");        

  Job list =  (Job)GetJobsForName(sched, "job1);     

System.Diagnostics.Debug.WriteLine(list.GetStatus());   

  return jobs; }

public static ADTObjects GetJobsForName(Scheduler connection, string jobName) {     JobByNameFilter filter = new JobByNameFilter(jobName);   

  Int32 recordCount = default(Int32);  

   filter.singleGroupOnly = false;    

 return connection.GetObjectsWhere(filter, 0, true, out recordCount); }

public class JobByNameFilter: IObjectRequestFilter    {       

 public string jobName = "";       

 public bool singleGroupOnly = true;      

  public JobByNameFilter(string jobName)        {  

          this.jobName = jobName;        }    

    public string GetTableName()        

{            return "job";        }        

public string GetSelectClause()      

  {            return "*";        }   

     public string GetWhereClause()      

  {            if (!singleGroupOnly)           

 {                //Search for all jobs matching this name, in all job groups                string query = "name='" + jobName + "'";               // System.Diagnostics.Debug.WriteLine(query);                return query;            }      

      //else we're looking for a single job, located in a specific group            System.Text.RegularExpressions.Match match = default(System.Text.RegularExpressions.Match);            //the name may be just the job name (in which case we look in the root group)            //or it may contain parent group information, delimited by "\"            match = System.Text.RegularExpressions.Regex.Match(jobName, "(?:(.+)\\\\){0,1}([^\\\\]+)");            if (!match.Success)            {                //it's an error, but let the server handle it.                return "name='" + jobName + "'";            }            if (match.Groups[1].Success)            {                //a group hierarchy was specified.                //match.groups(1) contains the group path, e.g., "group 1\group 1a"                //match.groups(2) contains the job name                //Search for the job with the specified name within the specified group.                //the jobGroup table has a "fullName" column that stores its full hierarchical name                return "name='" + match.Groups[2].Value + "' and jobGroup in (select OID from jobGroup where fullName='Root\\" + match.Groups[1].Value + "')";            }          

  else            {                //else there was no group information specified--the job is in the root.                //match.groups(2) contains the job name, and we search only in the root group,                //which always has the same OID.                return "name='" + match.Groups[2].Value + "' and jobGroup='{2C13CBB7-57D7-44A7-A74C-92B9F92A2A01}:{9A3EA996-9137-4EA7-8CAC-55E70695B473}'";            }     

   }        public string GetOrderClause()        {            return "";        }    }

Bill Staff (601 posts)
April 28, 2017 02:55 PM
Accepted Answer

You are calling GetJobsForName, which returns a collection of objects. You need to iterate through the collection and process each object separately.

Or use the GetJobForName, which returns a single job (and does the cast for you).

User5099 (22 posts)
May 2, 2017 02:25 PM
Accepted Answer

Thanks Bill.

Could you please let me know if is there a  way to see the query that is being built in the console/output window when we call "(filter, 1, true, out recordCount) " method  and it successfully returns the output ? 

Bill Staff (601 posts)
May 3, 2017 06:16 AM
Accepted Answer
There is no way to see the database query from the client. If you turn on diagnostic logging on the server, you can review the logs and see the queries that are being executed. You can download database schema documentation from the API page.
User5099 (22 posts)
May 3, 2017 07:54 AM
Accepted Answer

Thanks Bill. This will help me a lot.

I have one final query. Could you please let know if is it possible to all jobs in a list instead of getting individual jobs by names?

Bill Staff (601 posts)
May 3, 2017 08:15 AM
Accepted Answer

To get all jobs on the server, you can use GetObjectsForClass with the CID parameter set to CID_Job.

User5099 (22 posts)
May 3, 2017 08:17 AM
Accepted Answer
Thanks a lot Bill.
User5099 (22 posts)
May 3, 2017 09:46 AM
Accepted Answer

Hi Bill,

Sorry, I have to come back again :). I am able to return the IADTObjects successfully and on looping those objects I am getting jobs as well but for each and every job I want to get the status as well. Since both status and jobname are in different classes, is there any way I can get them or do I have to explicitly perform join in IObjectRequestFilter Interface ?

Please find my code below

IScheduler sched = app.ConnectRemote("", "", "");

IADTObjects jobList = GetAllJobs(sched);

foreach(IJob job in jobList) {    

 System.Diagnostics.Debug.WriteLine(job.Name);

}

 

public static IADTObjects GetAllJobs(IScheduler sched) {    

 IADTObjects objects = default(IADTObjects);   

  try     {           

 objects = sched.GetObjectsForClass(ClassIDEnum.CID_Job);    

 }catch(Exception e)     {     

    Console.WriteLine(e.StackTrace);    

 }     

return objects; }

Bill Staff (601 posts)
May 3, 2017 11:55 AM
Accepted Answer
You don't have to do anything else with the object request. Once you have the job (as an IJob), call GetStatus to get the status object. Since you  just fetched the job from the server it will have the latest status, so you can call GetStatus(false). Calling GetStatus(true) refreshes the status from the server.
User5099 (22 posts)
May 3, 2017 01:03 PM
Accepted Answer
Thanks Bill, its working :)
User5099 (22 posts)
May 4, 2017 11:30 AM
Accepted Answer

HI Bill, 

Everything works perfectly now. Thank you.

But When I run the application on an average it takes around 2 to 2 and half minutes to get ADTObjectas and looop throught them. I have a total of 312 jobs and I am working on AdTempus 3.0.

please find my code and time taken for reference

1) Get All Objects

Time taken: 00:01:11.0401033

IADTObjects objects = sched.GetObjectsForClass(ClassIDEnum.CID_Job);

 

2) Loop Through them

  Time Taken: 00:01:19.4760468

IADTObjects jobList = GetAllJobs(sched);

  foreach (IJob job in jobList) {                 

  AdTempusDto adtempusDto = new AdTempusDto();  

           IJobStatus jobStatus = job.GetStatus(); 

           adtempusDto.id = job.OID;              

       adtempusDto.name = job.Name;        

           adtempusDto.path = job.Group.ToString();    

               adtempusDto.status = jobStatus.Status.ToString();    

               adtempusDto.jobQueue = job.JobQueue.ToString();  

                 adtempusDto.description = job.Description;     

              adTempusJobsList.Add(adtempusDto);}

 Could you please let me know if it takes this time or Am I doing something wrong here?

 

Bill Staff (601 posts)
May 4, 2017 12:42 PM
Accepted Answer

It wouldn't surprise me that your initial call to GetObjectsForClass takes awhile. It should take about as much time as the Console takes to load the jobs list when you first start it. The server is instantiating all of the jobs (and their related objects) and sending them all over. There are several inefficiencies in the way it's designed.

Looping through them should not be taking much time--nothing in your code should be making a call to the server. Are you sure you're not making two calls to GetObjectsForClass somehow?

If you are going to be fetching the jobs more than once in the same session, then I recommend this approach to take advantage of the client-side caching in the API:

  1. When your application starts, call Scheduler.PrimeCache. This will send over all the jobs from the server, and they'll be cached on the client.
  2. In your GetAllJobs method, Use GetObjectsForClassFromCache instead of GetObjectsForClass. This will fill the request from the cache rather than doing another fetch from the server.
  3. Use Job.GetStatus(false) to get the status.
  4. The next time you need to update your list, call Scheduler.RefreshObjects(). This will send over only changes that have been made since your last call (new and modified jobs, updated statuses, etc.)
  5. Then call GetObjectsForClassFromCache again and Job.GetStatus(false). Neither of those should produce a server call.

If you're going to be running this from a Web server or something else stateless where you can't take advantage of caching, you may be better off just doing a direct database read. This SQL query should give you the same information:

select j.name as JobName, j.oid as JobOID,s.stringText as StatusDescription,g.name as GroupName,q.name as QueueName,j.description as JobDescription
from job j join jobstatus js on j.status=js.oid
join StatusStringsEN s on js.status=s.stringID
join jobgroup g on j.jobGroup=g.oid
join JobQueue q on j.jobQueue=q.oid

The only tricky part is that the Group name will be only the name of the lowest level of the hierarchy. To get the full hierarchy you will have to write code follow up the chain. (There's a FullName column in the JobGroup table but I don't think it's updated reliably; you can check your database to confirm though.)

User5099 (22 posts)
May 4, 2017 01:00 PM
Accepted Answer

Hi Bill,

Thanks a lot for a detailed information. 

I am planning on running from stateless state where I can't take advantage of caching. Currently, I am going to use the above query you provided me for now. 

Could you please let me know if is there any chance I would able to run this from Web Server or web application(stateless web page) and can take advantage of caching if I migrate to AdTempus4.0 ?

Bill Staff (601 posts)
May 4, 2017 01:44 PM
Accepted Answer
For version 4 the server and the API have much better performance and do not rely on client-side caching. You will see better results with that version but it still won't be as fast as going to the database directly, since going through the API adds additional layers.
User5099 (22 posts)
May 4, 2017 02:09 PM
Accepted Answer
Thank You Bill.

Replies are disabled for this topic.