user-defined variable in VB script and email attachments issue

TJ (32 posts)
October 5, 2020 09:12 AM
Accepted Answer

Hi Bill,

I am facing to two issues when tackling a set of steps.

I have three steps and each of them executes a batch process which populates output respectively.(the output will not be send out in the step until the fourth step)

The execution of fourth step is not dependent on the previous three steps, however, the exit code of the fourth step will take all results of previous three steps into account.  

The fourth step moves all three outputs from previous steps to a designated archive location (the step also create a new folder named with current system timestamp), and most important is to send out email notification with outputs per the exit code.

I created a variable called 'RC' - integer - value 0. My idea is to set this variable accordingly after each of three steps. On the fourth step, I'll use a VB script to evaluate RC, True to enable step succeed and false to enable step failed. It will be a very simple script as below.

 Now I am facing two issues:

1. the script does not seem work to evaluate RC -> Is my VB script wrong? 

2. the fourth step does not attach the reports I moved to the designated archive location in email notification. -> I checked "include subdirectory" and "attach files since the job started".

 

Public Overrides Function Run() As Object
  If adTempus.JobVariables("RC") = 0 Then
        'Return True to trigger the job, or False to not trigger the job.
      Return True
  Else
      Return False
  End If
    End Function 

 

Bill Staff (602 posts)
October 6, 2020 08:30 AM
Accepted Answer

In what way does your script not work? Where are you using the script--Response, Success Rule, Step Condition, ... ?

Even though you define the variable as an integer, the JobVariables collection accessor returns everything as a string, so you need to use

If adTempus.JobVariables("RC") = "0"

or

If CInt(adTempus.JobVariables("RC")) = 0

I would need to know more about your setup to answer question 2. But note that if the file was created or modified before the job started and you move it into the folder that the email notification attaches from, it's not going to get picked up, because it hasn't been modified (moving files does not update their modification timestamp).

TJ (32 posts)
October 7, 2020 08:26 AM
Accepted Answer

Thank you for your reply.

I think this If adTempus.JobVariables("RC") = "0"  would work, I did not know jobVariables converts Integer to string again.

for the second question, all the outputs are populated from the steps of this job, the last step is to move those outputs only. To conclude, they were created after the job started, they were moved within the same job and email notification is the response of "move" step. Is there a way to debug this at my end?

 I have an additional question, I aim to create different string variables in adtempus which are updated by different return code from scripts. for example, if I would be able to return an array from my script, How would I pass each element to different variables that I defined in adtempus? How to link them together array[0] -> RC1, array->RC2, and so on

Bill Staff (602 posts)
October 7, 2020 02:23 PM
Accepted Answer

It turns out that the user interface is wrong: if your Response is defined at the step level and you check that option, it is comparing the file timestamp to the step start time, not the job start time. The solution to this in your case is to define your Response at the job level instead.

There is (almost) a simpler way to do this if you are using the adTempus file transfer task to do the copy. The notification action should be able to take the list of files processed by the file copy, without having to do a separate scan of the folder. There's a bug that's preventing this from working. If you'd like to explore this approach, open a support case and we can do a bug fix to get this working. Include an export of your job so we can see how you're doing things and make sure the idea will work.

I don't fully understand your last question, but job variables can't natively handle arrays. You'd have to combine the values using some sort of delimiter. If you're trying to look at results from multiple steps, adTempus does create a separate variable holding the exit code from each step. The variables are named "Stepx.ADTTaskResult" where x is the step number. So if you want to look at the exit codes from the first 3 steps, you would look at "Step1.ADTTaskResult", "Step2.ADTTaskResult", and "Step3.ADTTaskResult".

After your job runs, the instance will have a Captured File named "Job Detail Log". At the end of the log it lists the final values of all the job variables. You can use this to see what variables are available, or to troubleshoot problems with variables.

TJ (32 posts)
October 8, 2020 07:13 AM
Accepted Answer

Thank you so much, Bill!

Email notification attachment worked when I define response on Job level, it picked up all files the job has created.

I am aware of  adtempus job variable "Stepx.ADTTaskResult", but I am expecting a complicated result situation. So it will return different numbers, for instance, 1-> "execution result failure"; 2 -> "file not found"; 3 -> "duplicate file"; 0-> success.  I will return one of them and define exit code between 1 and 3 as step failed. In the mean time, I want to update a string variable with the failure reason according to the actual return code [0,1,2,3]. So later on, I can plug in this string variable in email notification like "The execute failed due to %variable".

I am not sure if it is feasible in adtempus. Or you have better idea to achieve it. My ultimate goal is to plug in the failure reasons which we captured from script in the email that sent by adtempus. Initially, I was thinking of passing an array with different return code and assign array element a[0], a[1] to adtempus variables. But you said job variables cannot natively handle array.

Bill Staff (602 posts)
October 9, 2020 08:50 AM
Accepted Answer

Oh, now I understand. Your program (or script?) is returning an exit code, and in your email notification you want to convert that numeric value to a string error message.

You can do this using an inline function.

Edit the "InlineFunctions" Script library and add this code before the end of the Module:

    ReadOnly ExitCodeMessages As String() = New String(){
    "Success",
    "Execution result failure",
    "File not found",
    "Duplicate file"
    }
    Public Function GetMessageForExitCode(exitCode As String) As String
        Dim nExitCode=CInt(exitCode)
        
        If nExitCode<0 OrElse nExitCode>=ExitCodeMessages.Length Then
            Return "Unrecognized exit code"
        End If
        
        Return ExitCodeMessages(nExitCode)
    End Function

In the email notification you can call the function with the result you want to get the message for by using the inline function call syntax. For example you can include this in the message body:

The result was %=GetMessageForExitCode(%Step1.ADTTaskResult%)%

You can also use %ADTTaskResult% without the step prefix to get the exit code for the current/most recent step.


TJ (32 posts)
October 13, 2020 09:45 AM
Accepted Answer

Hi Bill,

I am still not very clear about the resolution.  

When my program returns numeric value, how would they map to the strings that I define in this InlineFunctions?

And is this InlineFunctions built-in for email notification or I need to invoke it for response?

 

Thank you again. 

Bill Staff (602 posts)
October 13, 2020 09:49 AM
Accepted Answer

You may the numeric value to the string by calling the GetMessageForExitCode method. You can do this anywhere you can insert a Job Variable in adTempus using the syntax I showed. For example, put this in the message body for your email notification:

%=GetMessageForExitCode(%Step1.ADTTaskResult%)%

If Step1.ADTTaskResult is 0, this will be replaced with "Success" in the message.

TJ (32 posts)
October 14, 2020 02:27 PM
Accepted Answer

Now I understand. It is working for me now. I was able to get one execution as I've expected. However, when I kicked off a second run, I did not get email notification. I did not make any change between. Is there a way to troubleshoot on my own? I am attaching screenshot here, not sure if you can see it at your end

 

Bill Staff (602 posts)
October 14, 2020 05:52 PM
Accepted Answer

Where is this Response being run--from the step or at the job level?

What Event(s) are configured for the Response (job end, job failed, job succeeded, ...)? Were the events satisfied?

If you think the events are all set up correctly, check the Messages tab for the job and see if there was an error reported when adTempus tried to send the email.

Other than that I can't tell you anything without seeing the configuration of the Response and the details of the job and step statuses.

TJ (32 posts)
October 16, 2020 12:14 PM
Accepted Answer

I've got that issue resolved.

Sorry for bothering you again. With the requirements are getting clearer, I am facing another dilemma. I am hoping to get another variable out of my Perl script and pass it to adtempus - if adtempus allows me (utilize one of adtempus build-in variable or pass to my own defined variable).

For instance, the last line of my perl script is exit($return, $filename), I am hoping to pass $filename to a variable "FILENAME" in adtemps. Then in email, I can insert  %FILENAME% in email body. so it would say  "The result for file %FILENAME% was %=GetMessageForExitCode(%Step1.ADTTaskResult%)%

 Is this feasible? 

Bill Staff (602 posts)
October 16, 2020 01:35 PM
Accepted Answer

No, that won't work. The Perl process that's running the script can only return a numeric exit code. There's no way for Perl to communicate back to adTempus directly, unless you can load a .NET assembly from Perl.

There are a few ways you can handle this. If your script is being called once for each file, then you already know the file name in adTempus before you call the script, so you don't need the script to pass it back.

If the script is handling multiple files and you need to pass back the name of just one of them, then you will need to pass the information back to adTempus by writing it to a file (or to stdout) and then reading it using another script in adTempus.

If you want to write it to a file, you should have your script write to a fixed file name in the directory specified in the "ADTJobTemp" environment variable. This is a temporary directory created for the job and removed after execution. You would then need a .NET script that runs in adTempus to read the file, get the information, and put it in a variable. For example, your script would write to "%ADTJobTemp%\scriptoutput.txt" and then a script in adTempus would read from that file.

You could also have it write to the console (stdout) and set the "capture console" option in adTempus. When you do that, the name of the file that contains the captured out will be stored in the "JobStep.CapturedConsoleFileName" job variable after the task finishes. Again, you would need to write a script in adTempus to read the file, extract the content, and put it in a variable.

Maybe the simplest way is if we write you a little command-line driven program that you could call from your Perl script, that would let you set the job variable by passing command-line arguments to it. That would save some hassle for you.

TJ (32 posts)
October 17, 2020 06:12 PM
Accepted Answer

I am using the last approach you've suggested.

Public Function GetFilenameFor(filename As String) As String
  Dim FilePath As New System.IO.StreamReader(filename)
  
        Dim FileContent As String = FilePath.ReadToEnd()
  Return FileContent
  
    End Function

 It does not produce any result when I use %=GetFilenameFor(%JobStep.CapturedConsoleFileName%)% in my email.

 

In order to make sure my vb script is correct, I replaced  Dim FilePath As New System.IO.StreamReader(filename) with a static path Dim FilePath As New System.IO.StreamReader("D:\CGISupport\install_solr_service.txt")

I was able to get the file content of the .txt file by using  %=GetFilenameFor()%

 

I also tested job variable %JobStep.CapturedConsoleFileName%, it does produce the path of console file.

Is the type of variable JobStep.CapturedConsoleFileName String?

Bill Staff (602 posts)
October 19, 2020 09:42 AM
Accepted Answer

I should have thought it through a little more. Since you're doing your notification from the Job level, the JobStep.CapturedConsoleFileName variable is no longer defined when you get to that point (it's only defined while the step is running). Instead you're going to need to run a script at the end of each step to save the information so to use later.

I suggest you create a Shared Script named "ReadCapturedOutput" with this code:

Imports System
Imports System.Collections.Generic
Imports ArcanaDevelopment.adTempus.Shared
Imports ArcanaDevelopment.adTempus.ApplicationIntegration

Public Class UserScript
    Inherits ArcanaDevelopment.adTempus.ApplicationIntegration.UserScriptBase

    Public Overrides Function Run() As Object

        Dim fileName=adTempus.JobVariables("JobStep.CapturedConsoleFileName")
        Dim content=System.IO.File.ReadAllText(fileName)
        Dim stepNumber=adTempus.JobVariables("ADTStepNumber")
        Dim variableName=String.Format("Step{0}.CapturedOutput",stepNumber)
        adTempus.JobVariables.Add(variableName, content, False)
        Return 0
    End Function
End Class

At the end of each step where you're running your Perl script, add a Response that runs with event "Step Ended" (so it will always run). Add a Script Action that runs the Shared Script you created above. This will read the captured console output for the step and save it to a variable named "Stepn.CapturedOutput". In your email message you can then insert "%Stepn.CapturedOutput%" instead of calling an inline function.

TJ (32 posts)
October 26, 2020 08:00 AM
Accepted Answer

I ended up using this approach you suggested "write the content to a file in my program, then created a function within inlinefuction to read the content of that file, in email notification, I %=xxxx% to get the value.

I just noticed another thing, adtempus does not allow define success scenarios with a combination of exit code using 'AND, OR', like exit code = 0 or exit code =5, exit code = 0 and exit code =5.

 

Bill Staff (602 posts)
October 26, 2020 10:12 AM
Accepted Answer

A program can only have one exit code, so an "and" condition isn't applicable. If you can't use a range (e.g., "between 0 and 5") then you can select the option to "Use a script" to determine success and check the value in the script:

Imports System
Imports System.Collections.Generic
Imports ArcanaDevelopment.adTempus.Shared
Imports ArcanaDevelopment.adTempus.ApplicationIntegration


Public Class UserScript
    Inherits ArcanaDevelopment.adTempus.ApplicationIntegration.SuccessRuleScriptBase

    Public Overrides Function Run() As Object
        Return Parameters.ExitCode=0 OrElse Parameters.ExitCode=5 
    End Function
End Class

 

TJ (32 posts)
November 13, 2020 12:03 PM
Accepted Answer

Sorry, this is taking so many rounds of back and forth.

Right now, I am trying to combining the result of three steps using a script to trigger SUCCESS and FAILURE events. I thought this would Ok. But apparently it does not work as expected. There are below two scenarios I want it to trigger SUCCESS event. I flip the True to False for Failure event.

If (adTempus.JobVariables("Step1.ADTTaskResult") ="0" And adTempus.JobVariables("Step2.ADTTaskResult") ="0" And adTempus.JobVariables("Step3.ADTTaskResult") ="0")
   Return True
  ElseIf(adTempus.JobVariables("Step1.ADTTaskResult") ="1" And adTempus.JobVariables("Step2.ADTTaskResult") ="2" And adTempus.JobVariables("Step3.ADTTaskResult") ="0")
   Return True
  Else
   Return False
  End If 

 

Bill Staff (602 posts)
November 13, 2020 12:26 PM
Accepted Answer

What isn't working? Where are you running this script--as a step? As a Response? As a Success Rule script? Originally you wanted your 4th step to evaluate the exit codes from the previous steps. Is that what we're talking about? What does step 4 do--is it running a perl script like the others? Running an adTempus script? Running an adTempus file transfer?

It would probably be quicker if you open a support case and send an export of what you have so far for your job so I can better understand what you're doing.

TJ (32 posts)
November 13, 2020 01:42 PM
Accepted Answer

I am running the script as a condition to trigger job SUCCESS and job FAILED in job level response.

I am evaluate the combination of exit code of each step.   

 the first condition only if all three steps return 0, it will trigger response as SUCCESS.

adTempus.JobVariables("Step1.ADTTaskResult") ="0" And adTempus.JobVariables("Step2.ADTTaskResult") ="0" And adTempus.JobVariables("Step3.ADTTaskResult") ="0

 

the second condition only if step 1 returns '1', step2 returns '2' and step 3 returns '0' to trigger SUCCESS

 adTempus.JobVariables("Step1.ADTTaskResult") ="1" And adTempus.JobVariables("Step2.ADTTaskResult") ="2" And adTempus.JobVariables("Step3.ADTTaskResult") ="0

 

Any other situations will trigger FAILED.

 

I ran it and the exit code was step1 = 1, step2 = 0, step 3 = 0, it was supposed to trigger FAILED as it does not meet the two conditions I gave.

but it turned out to be SUCCESS.

I am not sure what I am doing wrong here. 

Bill Staff (602 posts)
November 14, 2020 10:25 AM
Accepted Answer

Still not sure exactly how you have the Response set up, but I don't think there's a way to make it work with a job-level Response because the "Job Ended" event happens after everything is finished for the job--it's too late to change the success/failure status at that point. What you need is an event that happens after the steps finish but before success/failure determination, and there isn't an event that does that.

You could move your Response to the last step and then it would work. Another way to do it would be to add a final step that runs a version of that script and then returns an exit code to indicate success or failure, which would cause the step to succeed or fail. Since it's the last step, the job's success or failure status would be based on that result.

So step 5 would be a Script Execution Task that runs this script:

Imports System
Imports System.Collections.Generic
Imports ArcanaDevelopment.adTempus.Shared
Imports ArcanaDevelopment.adTempus.ApplicationIntegration

Public Class UserScript
    Inherits ArcanaDevelopment.adTempus.ApplicationIntegration.ResponseEventScriptBase

    Public Overrides Function Run() As Object

        Dim step1Result=adTempus.JobVariables("Step1.ADTTaskResult")
        Dim step2Result=adTempus.JobVariables("Step2.ADTTaskResult")
        Dim step3Result=adTempus.JobVariables("Step3.ADTTaskResult")

        If step1Result ="0" AndAlso step2Result ="0" AndAlso step3Result ="0" Then
            Return 0
        ElseIf step1Result="1" AndAlso step2Result="2" AndAlso step3Result="0" Then
            Return 0
        Else
            adTempus.LogMessage(MessageTypeEnum.Warning,0,String.Format("Failing job because steps 1-3 returned {0}, {1}, {2}",step1Result, step2Result, step3Result))
             Return 1
        End If 
    End Function
End Class

Replies are disabled for this topic.