For example, consider running a forecast pipeline in Oracle EPM, we often deal with multiple forecast periods that need to be processed sequentially.
However,
ensuring that each period runs correctly, waiting for previous jobs
to complete, and handling errors gracefully can be tricky.
In
this the script ensures that each forecast period is processed properly,
one at a time, and prevents overlapping or conflicting jobs.
Why
Do We Process Forecast Periods One by One?
Imagine
you’re running a forecast data load for an entire fiscal year, where
each period represents a month or quarter.
#
You don’t want multiple forecast periods running at the same time—this
could cause data conflicts.
# You need to wait for each job to
finish before starting the next one.
# If a job fails, you want to detect it early and stop execution.
This script does all of that automatically!
Initializing the Last Job ID
At
the start of the process, we initialize a variable to keep track of the
last job that was submitted:
String LAST_JOB_ID = "" // Initialize
- If a job
is still running, we wait for it to finish before starting a new one.
- If a job
fails, we detect the failure and stop processing further.
- We use
this variable to control job execution flow.
Looping
Through Forecast Periods
We
loop through each forecast period (up to 8 periods in this case).
for
(int i = 1; i <= 8; i++) {
try {
println "Checking forecast period
${i}"
- The
script iterates over 8 forecast periods one by one.
- For each
period, we retrieve important details like:
- Month
- Year
- Quarter
Fetching
Forecast Period Details
For
each period, we retrieve the corresponding substitution variables:
String
monthVar = "Fcst_Per${i}"
String
yearVar = "Fcst_Per${i}_Yr"
String
quarterVar = "Fcst_Qtr${i}"
String
fcstMonth =
operation.application.getSubstitutionVariableValue(monthVar).toString()
String
fcstYear =
operation.application.getSubstitutionVariableValue(yearVar).toString()
String
fcstQuarter =
operation.application.getSubstitutionVariableValue(quarterVar).toString()
- These
values tell us which forecast period we are working on.
- If the
values are missing or invalid, we skip the period (as shown in the
next step).
Skipping
Periods That Don’t Match the Forecast Year
if
(fcstYear != forecastYear) {
println "Skipping period ${i} as it
does not match forecast year $forecastYear."
continue
}
- If the forecast
year for the period doesn’t match the expected year, we skip it.
- This
prevents us from processing data for the wrong year.
Skipping
Invalid Periods
if
(fcstMonth == "-" || fcstYear == "-") {
println "Skipping period ${i} due to
invalid values."
continue
}
- If the forecast
month or year is missing ("-"), we skip this period.
- This
avoids running the job with incomplete data.
Waiting
for Previous Job to Finish Before Starting a New One
if (LAST_JOB_ID && LAST_JOB_ID.isNumber()) {
boolean jobRunning = true
int checkAttempts = 0
while (jobRunning && checkAttempts
< 100) {
sleep(5000)
String activeJobStatus =
getJobStatus(connectionNamedm, LAST_JOB_ID)
if (activeJobStatus ==
"RUNNING") {
println "Waiting for previous
job to finish before starting Forecast Period $i..."
} else if (activeJobStatus ==
"FAILED") {
println " Warning: Previous
Pipeline Job ($LAST_JOB_ID) failed. Moving to next period immediately."
break
} else {
jobRunning = false
}
checkAttempts++
}
}
- Before
submitting a new job, we check if the last submitted job (LAST_JOB_ID)
is still running.
- We wait
for the job to finish, checking every 5 seconds (using
sleep(5000)).
- If the
job fails, we print a warning and move to the next period.
Submitting
a New Pipeline Job
If
everything looks good, we submit a new job for the forecast period:
HttpResponse<String>
jsonResponse = operation.application.getConnection(connectionName)
.post()
.header("Content-Type",
"application/json")
.body(json([
"jobName": "Job
Name",
"jobType":
"pipeline",
"variables": [
"FCST_Month_1":
fcstMonth,
"FCST_Year_1": fcstYear,
"FCST_Period_1":
fcstPeriod,
"FCST_Qtr_1":
fcstQuarter,
"IMPORTMODE":
"Replace",
"EXPORTMODE":
"Merge",
"ATTACH_LOGS":
"Yes"
]
]))
.asString()
- The job
uses important variables such as:
- Forecast
Month, Year, and Quarter
- Import
and Export Modes
String
jobId = ctx.read('$.jobId')
if
(jobId == null || jobId.toString().trim().isEmpty()) {
println " Error: Retrieved empty job
ID for period ${fcstPeriod}. Skipping..."
continue
}
LAST_JOB_ID
= jobId.toString()
println
"Stored LAST_JOB_ID: ${LAST_JOB_ID}"
- We
extract the job ID from the API response and store it in
LAST_JOB_ID.
- This ID
is used to track and wait for job completion in the next iteration.
Ensuring
Job Completes Before Moving to Next Period
boolean
isComplete = waitForCompletion(connectionName, LAST_JOB_ID, "Pipeline
Job")
if
(!isComplete) {
throwVetoException(" Pipeline job
failed for forecast period ${i}. Stopping execution.")
}
- The
script waits for the job to complete before moving to the next
period.
- If the
job fails, we abort execution immediately.
This
script ensures that forecast periods are processed in order, preventing overlapping
jobs and handling errors gracefully.
✔ Prevents multiple forecast jobs
from running at the same time.
✔ Automatically waits for previous
jobs to complete before starting new ones.
✔ Detects job failures and stops
execution if something goes wrong.
✔ Handles missing or invalid data
properly.
This makes your Oracle EPM automation more reliable and prevents unwanted surprises in forecast processing!
The Complete script is here
Happy days on the Cloud!!!
No comments:
Post a Comment