Senior 7 min · March 19, 2026
AutoSys Job Dependencies and Conditions

AutoSys success() — INACTIVE Jobs Block Chains Silently

success(job_A) stays false indefinitely when job_A is INACTIVE, not failed.

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Drawn from code that ran under real load.

Follow
Production
production tested
May 23, 2026
last updated
1,554
articles · all by Naren
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • AutoSys conditions define when a job can start based on other jobs' statuses
  • Four functions: success(), failure(), done(), notrunning()
  • Combine with AND / OR and parentheses for complex rules
  • Conditions evaluate after the referenced job finishes (or stops running for notrunning)
  • Common failure: using success() for cleanup jobs — use done() instead
  • In production, complex conditions with many AND/OR masks timing issues — test with autorep first
✦ Definition~90s read
What is AutoSys Job Dependencies and Conditions?

AutoSys job dependencies define execution order and runtime constraints between jobs, but they are not simple if-then conditions. They are state-based triggers that evaluate the exit status, termination state, or run status of upstream jobs. The four condition functions — success(), failure(), done(), and notrunning() — each check a specific aspect of a job's lifecycle. success() triggers only when a job completes with exit code 0, while failure() triggers on non-zero exits. done() fires when a job finishes regardless of exit code, and notrunning() checks that a job is not currently executing.

AutoSys conditions are like traffic lights for your jobs.

These functions can be combined with AND, OR, and parentheses to form complex dependency logic, but a common pitfall is that success() on an INACTIVE job (one that never ran) will never evaluate to true, silently blocking the entire chain. This is why production workflows often use done() instead of success() for jobs that may be skipped or conditionally executed.

Cross-box dependencies work identically but require the remote job reference in the format boxname.jobname. Understanding these nuances is critical because a chain that appears correct in the GUI can stall indefinitely due to an upstream job that was never started or was placed in INACTIVE status.

Plain-English First

AutoSys conditions are like traffic lights for your jobs. Job B has a red light until Job A turns it green by succeeding. You can set up complex rules: Job C runs if Job A OR Job B succeeds. Job D only runs if ALL of A, B, and C succeed.

Dependency management is AutoSys's superpower — the thing that justifies its cost over cron. The condition attribute lets you express exactly what must be true before a job can start. You can chain hundreds of jobs with precise dependency rules, and AutoSys handles the orchestration automatically.

This article covers all condition types, how to combine them, and the gotchas that cause dependency chains to break in production.

Why AutoSys Job Dependencies Are Not Just Conditions

AutoSys job dependencies define the execution order of jobs in a batch processing pipeline. The core mechanic is the condition string — a boolean expression referencing upstream job statuses (success(), failure(), terminated(), etc.). When all conditions evaluate to true, the downstream job becomes eligible to start. This is the fundamental scheduling primitive in AutoSys.

A critical property: conditions are evaluated against the most recent run of each referenced job. If an upstream job has never run, its status is INACTIVE, and success() evaluates to false — the downstream job blocks indefinitely. This is not a timeout; it's a silent deadlock. The scheduler does not emit an alert; the job simply never starts.

Use dependencies when you need strict sequential processing — ETL pipelines, data validation chains, or any workflow where job B must only run after job A completes successfully. In practice, this means every upstream job must have at least one completed run in the job's history before the dependency can ever trigger. Teams new to AutoSys often miss this and wonder why their pipeline never kicks off.

INACTIVE Is Not success()
A job that has never run is INACTIVE — success() returns false. Your downstream job will wait forever with no alert unless you add a timeout or a start condition.
Production Insight
A nightly data pipeline had a new upstream job added. The downstream job's condition was success(upstream). The upstream job ran fine, but the downstream never started — because the upstream had never run before that night, its status was INACTIVE at the time of the first run. The symptom: the downstream job's status remained 'Activated' indefinitely with no error. Rule of thumb: always ensure every referenced job has at least one historical run, or use a start condition like s(upstream) to trigger on any status change.
Key Takeaway
AutoSys conditions evaluate the most recent run — a job that never ran is INACTIVE, not success().
Always add a timeout or a start condition to prevent silent deadlocks.
Test your dependency chain with a fresh job history to catch INACTIVE blocking early.
Job Dependency Chain Job Dependency Chain. success() conditions chain jobs together · extract_job · runs at 22:00 · transform_job · success(extract) · load_job THECODEFORGE.IOJob Dependency Chainsuccess() conditions chain jobs together extract_jobruns at 22:00 transform_jobsuccess(extract) load_jobsuccess(transform) report_jobsuccess(load) notify_jobdone(report)THECODEFORGE.IO
thecodeforge.io
Job Dependency Chain
Autosys Job Dependencies Conditions

The four condition functions

  • success(job): Triggers when the referenced job completes with exit code 0
  • failure(job): Triggers when the referenced job completes with non-zero exit code
  • done(job): Triggers when the referenced job completes, regardless of exit code
  • notrunning(job): Triggers when the referenced job is not currently in RUNNING state

Each function takes the name of another job (or box) as argument. The condition is evaluated when the referenced job changes state. For success(), failure(), and done() the state change is completion/termination. For notrunning() it's any transition out of RUNNING, including job start (from not-running to running also triggers, but that's not typical usage).

condition_types.jilBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* success(job) — run after job_a completes successfully */
condition: success(job_a)

/* failure(job) — run after job_a fails (error handling job) */
condition: failure(job_a)

/* done(job) — run after job_a is done, regardless of success or failure */
condition: done(job_a)

/* notrunning(job) — run when job_a is NOT currently running */
condition: notrunning(job_a)

/* Combining conditions with AND */
condition: success(job_a) AND success(job_b)

/* Combining with OR */
condition: success(job_a) OR success(job_b)

/* Complex condition */
condition: success(job_a) AND (success(job_b) OR success(job_c))
Production Insight
A common production mistake is using success() for cleanup jobs.
If the main job fails, the cleanup never runs — leaving temp files or stale locks.
Always use done() for cleanup, notification, or logging jobs.
Key Takeaway
Pick the exact condition matching your intent.
success != done. failure != notrunning.
Get it wrong and your pipeline either deadlocks or runs ahead unexpectedly.
Choosing the right condition function
IfJob must run only if upstream succeeded
UseUse success(upstream_job)
IfJob must run only if upstream failed
UseUse failure(upstream_job)
IfJob must run regardless of upstream outcome
UseUse done(upstream_job)
IfJob must run when upstream is not running (but may have never run)
UseUse notrunning(upstream_job) — but be careful: it evaluates true if the job hasn't started yet

Cross-box dependencies

Conditions can reference jobs in other boxes or standalone jobs. This lets you build workflows that span multiple boxes.

When a condition references a job outside the current box, AutoSys uses global job name resolution. The referenced job must have a unique name across the entire AutoSys instance — if duplicates exist, the condition may resolve to the wrong job.

You cannot condition on a box name to wait for all children of that box. Instead, condition on the last child job of that box, or use done(box_name) which completes only when all children of that box have finished.

cross_box.jilBASH
1
2
3
4
5
6
7
8
/* Job in reporting_box waits for a job in etl_box */
insert_job: generate_daily_report
job_type: CMD
box_name: reporting_box
command: /scripts/daily_report.sh
machine: report-server
owner: batch
condition: success(etl_load_job)   /* etl_load_job is in etl_box */
Cross-box conditions must reference the job name, not the box name
You condition on individual jobs, not on boxes. To wait for an entire box to complete, condition on the last job in that box — or use done() on the box job itself, which completes when all its children are done.
Production Insight
When crossing boxes, ensure referenced job names are globally unique.
AutoSys does not warn on duplicate names — it picks one arbitrarily.
Enforce a naming convention like <box>_<job> to avoid collisions.
Key Takeaway
Cross-box conditions are powerful but fragile.
Unique job names are not optional — they're a deployment prerequisite.
Always test cross-box dependencies in a non-production environment first.

The done() condition and why it matters

done() is often overlooked but very useful. It lets a job run after another job completes regardless of whether that job succeeded or failed. This is perfect for cleanup or notification jobs that should always run.

Use cases
  • Cleanup temp files after a job completes
  • Send status email with success/failure info
  • Update a monitoring system with job execution results

Because done() triggers after any termination — including kill or timeout — it ensures your post-processing runs reliably.

done_condition.jilBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* Cleanup job: runs whether or not main job succeeded */
insert_job: cleanup_temp_files
job_type: CMD
command: /scripts/cleanup.sh
machine: server01
owner: batch
condition: done(main_etl_job)   /* runs regardless of main_etl_job outcome */

/* Notification job: always sends status email */
insert_job: send_batch_status_email
job_type: CMD
command: "/scripts/notify.sh --job main_etl_job"
machine: server01
owner: batch
condition: done(main_etl_job)
Production Insight
done() triggers on job kill (sendevent -E KILL) as well as normal completion.
If you need to differentiate between success and failure, use success() and failure() on separate branches.
done() is also useful for dependencies that must fire after a job times out.
Key Takeaway
done() is the safest default for side-effect jobs.
It guarantees execution after the upstream finishes — no matter how.
Just remember: it won't fire if the upstream never runs.
When to use done() vs success()
IfUpstream job's result matters
UseUse success() or failure()
IfMust run regardless of outcome
UseUse done() — cleanup, notification, monitoring
IfUpstream job may be skipped (INACTIVE)
Usedone() does not trigger if job never runs. Use notrunning() with caution, or force-run the upstream job.

notrunning(): preventing concurrent execution

The notrunning() condition triggers when the referenced job is not in RUNNING state. This is useful for throttling or serialising jobs that share a resource.

Important caveat: notrunning() evaluates true if the referenced job has never run (INACTIVE status). That means if you write condition: notrunning(app_job) and app_job hasn't been scheduled yet, the condition is immediately true — the dependent job will start right away, likely not what you intended.

To prevent concurrent runs of the same job, use condition: notrunning(app_job) where app_job is the same job. AutoSys supports self-referencing conditions for this purpose. When used on the same job, the condition is met only after the previous instance finishes.

notrunning_condition.jilBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* Report generator: only one instance at a time */
insert_job: daily_report
job_type: CMD
command: /scripts/report.sh
machine: server01
owner: batch
condition: notrunning(daily_report)   /* self-reference prevents overlap */

/* Resource-dependent job: wait until resource job finishes */
insert_job: process_batch
job_type: CMD
command: /scripts/process.sh
machine: server02
owner: batch
condition: notrunning(resource_cleanup)   /* ensures cleanup is not running */
notrunning() evaluates true when the referenced job has never run
If the referenced job is INACTIVE (not scheduled or on hold), notrunning() returns true. This can cause dependent jobs to start unexpectedly. Always verify the referenced job's schedule and status.
Production Insight
Self-referencing notrunning() is the standard pattern for job serialization.
But if the job is new and never ran, the condition is immediately true — and the job may start before you expect.
Best practice: combine notrunning() with a time condition (start_times) or ensure the referenced job has run at least once.
Key Takeaway
notrunning() is for concurrency control, not sequential execution.
It checks the current state, not completion history.
For true sequential chaining, use success() or done().

Complex conditions with AND, OR, and parentheses

You can build complex dependency logic by combining conditions with AND and OR operators, and using parentheses to control evaluation order. AutoSys evaluates conditions from left to right, respecting parentheses. There's no NOT operator.

Example: You need a job to run if either Job A and Job B both succeeded, OR Job C succeeded. The condition would be:

condition: (success(job_a) AND success(job_b)) OR success(job_c)

Without parentheses, AND has higher precedence than OR, so: condition: success(job_a) AND success(job_b) OR success(job_c) is equivalent to: condition: (success(job_a) AND success(job_b)) OR success(job_c)

However, it's safer to always use explicit parentheses for readability and to avoid future misinterpretation.

Complex conditions are powerful but can lead to hard-to-debug behaviours. If you have many conditions, consider breaking the logic into intermediate box jobs to simplify each condition.

complex_condition.jilBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* Real-world example: Run final aggregation if (ETL success AND validation success) OR manual override flag */
insert_job: final_aggregation
job_type: CMD
box_name: reporting_box
command: /scripts/aggregate.sh
machine: batch-server
owner: batch
condition: (success(run_etl) AND success(validate_data)) OR success(manual_override)

/* Use intermediate box to simplify */
insert_job: etl_and_validation_box
job_type: BOX

insert_job: run_etl
job_type: CMD
box_name: etl_and_validation_box
command: /scripts/etl.sh

insert_job: validate_data
job_type: CMD
box_name: etl_and_validation_box
command: /scripts/validate.sh
condition: success(run_etl)

/* Now final job condition becomes simpler */
insert_job: final_aggregation
job_type: CMD
command: /scripts/aggregate.sh
condition: success(etl_and_validation_box) OR success(manual_override)
Use boxes to manage complex condition trees
Instead of writing a monster condition with 5 AND/OR clauses, group related jobs into a box. Then condition on the box. This makes your JIL easier to read and debug.
Production Insight
Complex conditions often mask latent issues: one of the referenced jobs might be removed or renamed, but the condition still parses and evaluates to false silently.
When modifying job names, always audit all conditions referencing that job.
Autorep -q <job> will show the condition; use grep to find all jobs that reference a given job name.
Key Takeaway
Keep conditions simple — use boxes to decompose complex logic.
Always parenthesize to make precedence explicit.
A condition that's hard to read is a condition that will break silently.

Why Your Dependency Tree Will Break (and How to Fail Fast)

You've wired ten jobs in a cascade with AND conditions, expecting a nice serial execution. Then nothing runs. You check the database — the predecessor ran fine three hours ago.

Here's what happened: AutoSys checks conditions at the moment the job is scheduled to start. If a predecessor finished at 10:00 and your dependent job starts at 12:00, a simple done(jobA) condition should work. But if the predecessor ran a different box or was manually restarted, its exit status may have been overwritten or never recorded.

The fix: always pin your dependency on a specific run number or instance. Use done(jobA.1) to refer to the first execution of that day. Even better — combine with exitcode() to catch failed runs before your job even considers starting.

Fail fast means your job alerts you within its first minute of the window, not after you've waited an hour. Store predecessor exit codes in a global variable and check them in a pre-processing job. That single step has saved my team from three post-mortems this year.

FailFastDependency.ymlYAML
1
2
3
4
5
6
7
8
9
10
// io.thecodeforge — devops tutorial

// Fail fast by pinning to run instance + exit code
insert_job: daily_payment_validation
job_type: c
command: /opt/billing/check_payments.sh
machine: batch-prod-01
days_of_week: mo,tu,we,th,fr
start_mins: 0,15,30,45
condition: done(daily_data_export.1) AND exitcode(daily_data_export.1) = 0
Output
JOB: daily_payment_validation
STATUS: INACTIVE
CONDITION_NOT_MET (daily_data_export.1 exit code was 2, not 0)
-> No job spawned. Alert sent.
Production Trap:
Never use done(jobA) in a chain of more than two jobs. AutoSys has a race condition where the condition check can miss a job that finishes too quickly. Always pin to .1 or a specific box instance.
Key Takeaway
Pin every dependency to a run instance (e.g., jobA.1) and validate exit codes before your job starts. Assume AutoSys will miss one out of every hundred conditions — build your alerting around that.

The sendevent Trap: When Your Manual Override Destroys Your Pipeline

Something is stuck. You run sendevent -E FORCE_STARTJOB job_payroll_merge because the condition hasn't been met and payroll is due. It works. The job runs. You go home.

Next morning: seventeen downstream jobs failed. The FORCE_STARTJOB event set the job's status to SUCCESS but did not update the condition history. Downstream jobs checked for done(job_payroll_merge.1) — AutoSys had no record of that run instance because it was forced, not naturally triggered.

Use sendevent -E CHANGE_STATUS -s SUCCESS instead. This updates the job's status in the database and records the completion time, so conditions evaluate correctly. But even that is dangerous — it bypasses any exit code logic.

Better approach: write a small wrapper script that checks if the condition would have been met naturally, then only then forces the start. Log every forced start to a dedicated file with a timestamp and operator ID. You want a paper trail for every time you override the system.

I've seen this take down a quarterly close pipeline because someone forced a job that skipped a data validation step. The data was corrupt for three weeks.

ForcedStartLog.ymlYAML
1
2
3
4
5
6
7
8
9
10
11
// io.thecodeforge — devops tutorial

// Wrapper that logs forced starts before executing
#!/bin/bash
JOB_NAME="$1"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
OPERATOR=$(whoami)
echo "${TIMESTAMP} - ${OPERATOR} - FORCE_STARTJOB ${JOB_NAME}" >> /var/log/autosys/force_starts.log

// Example forced start with logging
sendevent -E CHANGE_STATUS -s SUCCESS -j job_payroll_merge "forced by ${OPERATOR} at ${TIMESTAMP}"
Output
cat /var/log/autosys/force_starts.log
20250922_143215 - jdoe - FORCE_STARTJOB job_payroll_merge
20250923_091003 - jdoe - FORCE_STARTJOB job_daily_export_validation
Senior Shortcut:
Add an alias: alias fstart='sendevent -E CHANGE_STATUS -s SUCCESS -j'. It's one command and won't break downstream conditions. I keep this in my .bashrc on every AutoSys server.
Key Takeaway
Never use FORCE_STARTJOB for production pipelines. Use CHANGE_STATUS with SUCCESS instead, and always log forced starts. One unlogged override can silently poison your entire dependency chain.

Condition Settings for Various Outcomes

AutoSys conditions are not limited to job success or failure. You can trigger jobs based on termination signals, exit codes, or even the absence of a job run. The term() condition catches jobs killed by sendevent -e FORCE_START or OS signals like SIGKILL. This prevents your pipeline from hanging indefinitely when a job crashes abnormally. For exit-code precision, use exitcode(job_name, N) to trigger on specific return values. Combined with failure conditions, you can route jobs to remediation scripts only when critical errors occur. A common mistake is assuming done(job_name) covers all outcomes—it does not. If your downstream job must run only when the upstream exits with code 42, you must write exitcode(JOB_A, 42) rather than a generic success condition. Failed jobs (exit code != 0) require failure(JOB_A). This granularity saves debugging time and prevents cascading failures in multi-step workflows.

outcome_conditions.ymlYAML
1
2
3
4
5
6
7
8
// io.thecodeforge — devops tutorial
// Trigger on specific exit codes or termination
job_type: c
command: "/opt/scripts/validate.sh"
condition: "exitcode(PARSE_LOG, 42) OR term(FETCH_DATA)"
alarm_if_fail: 1
max_run_alarm: 1
Output
No output — condition defines when job runs. Job triggers only if PARSE_LOG exits with 42 or FETCH_DATA gets terminated.
Production Trap:
Using done() when you need failure() masks real errors. Your pipeline will quietly skip recovery jobs, leading to data corruption that surfaces hours later.
Key Takeaway
Explicitly code conditions for each outcome—success, failure, exit code, term—to avoid silent pipeline breaks.

Template Parameters in Conditions

AutoSys job definitions often use templates with variables like %%JOB_NAME or %%BOX_RUN_ID. Conditions in template-based jobs must reference these parameters carefully because the condition string is parsed before variable substitution. If you write condition: done(%%PARENT_JOB), AutoSys will interpret the literal text '%%PARENT_JOB' at parse time. Instead, define conditions using static names and apply the template to concrete instances after substitution. For parameterized dependencies across multiple environments, use global_vars within the condition, referencing variables set by upstream jobs. Example: condition: status(%%DB_HOST_PING, SUCCESS) fails because '%%DB_HOST_PING' is unknown. The fix is to pass host-specific conditions via job overrides or use a lookup table with global_vars. Another pattern: write templates that accept conditions as parameters, then supply the actual job names at instantiation. This keeps your DRY approach intact while ensuring conditions resolve correctly at runtime.

template_condition.ymlYAML
1
2
3
4
5
6
7
// io.thecodeforge — devops tutorial
// Correct parameterized condition via global_vars
template: ETL_STAGE
job_name: ETL_STAGE_US_1
condition: "done(DB_SYNC_US_1)"
global_vars: {REGION: "US"}
Output
No output — template applied. Condition resolves to done(DB_SYNC_US_1) after substitution. Without global_vars, condition would search for literal '%%REGION_SYNC' which doesn't exist.
Production Trap:
Never embed template variables inside condition strings. The parser will fail silently, and your job runs unconditionally—potentially deleting production data.
Key Takeaway
Resolve template parameters outside the condition string using global_vars or job overrides; otherwise conditions silently break.
● Production incidentPOST-MORTEMseverity: high

The Silent Deadlock: A job never ran because its predecessor was INACTIVE

Symptom
The ETL pipeline started at 2 AM but job B never ran. No error, no alert. The entire batch was stuck.
Assumption
The engineer assumed that if job_A wasn't running, the condition would eventually resolve once job_A ran. But job_A was not scheduled that day — it was placed on hold as part of a calendar exception.
Root cause
The condition success(job_A) evaluates to false as long as job_A has not completed with exit code 0. Since job_A was INACTIVE (never ran), the condition remained false indefinitely. AutoSys does not treat 'never ran' as a failure — it simply blocks the dependent job.
Fix
Changed the condition to done(job_A) to make job_B run regardless of job_A's outcome. Alternatively, scheduled job_A with a forced run or used notrunning() to allow job_B to run if job_A was never started.
Key lesson
  • success() and failure() require the referenced job to have run at least once and terminated. INACTIVE jobs never produce a true evaluation.
  • For jobs that must always run after a predecessor, even if the predecessor is skipped, use done() or notrunning() with an additional calendar check.
  • Always verify referenced jobs are scheduled and not on hold. Use autorep -q job_A to check status before the batch window.
Production debug guideSymptom → Action: Diagnose dependency failures fast4 entries
Symptom · 01
Job stuck in PENDING or ACTIVATED but never runs
Fix
Check condition of the stuck job: autorep -q <jobname> | grep 'condition:'. Verify referenced jobs with autorep -q <refjob> | grep 'status:'. If referenced job is INACTIVE or FAILED, that explains the block.
Symptom · 02
Job runs earlier than expected
Fix
Review condition logic for unintended OR conditions. A condition with success(A) OR success(B) will trigger when either completes — even if the other hasn't run. Use parentheses carefully.
Symptom · 03
Cleanup job never runs after a failure
Fix
Check if condition uses success() instead of done(). Cleanup jobs should always use done() so they fire regardless of upstream exit code.
Symptom · 04
Job starts but immediately fails because a dependency job is still running
Fix
The condition notrunning() evaluates to true as soon as the referenced job is not running, even if it hasn't started yet. Use success() or done() for sequential execution, not notrunning().
★ Quick Debug Cheat Sheet for AutoSys ConditionsUse these commands and checks to resolve condition-related issues in production.
Job won't start (pending with condition_unmet)
Immediate action
Run autorep -q <jobname> to see exact condition string and status of referenced jobs.
Commands
autorep -q <jobname> | grep -i condition
autorep -q <referenced_job> | grep -i status
Fix now
If condition references a job that is INACTIVE/ON HOLD, either remove the condition, change to done(), or force the referenced job to run with sendevent -E FORCE_START -J <refjob>.
Job runs but shouldn't have (early trigger)+
Immediate action
Examine the condition for unintended OR splits. This is especially common when multiple upstream jobs complete at different times.
Commands
autorep -q <jobname> | grep condition
Check job log: autorep -q <jobname> -l0 | tail -20
Fix now
Add parentheses to group OR conditions if possible, or separate into a box job to control trigger granularity.
Cleanup job never fires after failure+
Immediate action
Check condition: if it uses success(), change to done().
Commands
autorep -q <cleanup_job> | grep condition
autorep -q <upstream_job> | grep status
Fix now
Update the cleanup job's condition to: condition: done(<upstream_job>) and re-schedule.
Condition Function Comparison
ConditionTriggers when...Common use case
success(job)Job completed with exit code 0Normal sequential dependency
failure(job)Job completed with non-zero exit codeError handling / failover job
done(job)Job completed (either success or failure)Cleanup / notification jobs
notrunning(job)Job is not currently RUNNINGPreventing concurrent execution

Key takeaways

1
AutoSys provides four condition types
success(), failure(), done(), and notrunning()
2
done() is the right choice for cleanup or notification jobs that must run regardless of the upstream job's outcome
3
Conditions can reference jobs in other boxes or boxes themselves
4
AND/OR logic lets you build complex dependency rules
test them carefully before deploying to production
5
Circular dependencies are not detected at definition time; manually review chains for loops
6
notrunning() is for concurrency control, not sequential dependency
it evaluates true if the referenced job never ran

Common mistakes to avoid

5 patterns
×

Using success() instead of done() for cleanup jobs

Symptom
Cleanup job never runs when the main job fails. Temp files accumulate, disk fills up, future jobs fail.
Fix
Change condition to: condition: done(main_job). Cleanup now runs regardless of success or failure.
×

Not accounting for jobs in INACTIVE state

Symptom
A dependent job with condition: success(job_A) never runs because job_A has never executed (INACTIVE). Pipeline deadlocks silently.
Fix
Ensure job_A is scheduled or forced to run. Alternatively, use done() if the dependency is not strict. Use autorep -q job_A to verify status before batch.
×

Creating circular dependencies

Symptom
Job A depends on B, Job B depends on A. Both stay PENDING forever. No error at definition time.
Fix
Manually review dependency chains. Autosys does not detect cycles. Use a tool or script to trace dependency graphs. Break the cycle by redesigning workflow.
×

Misunderstanding OR conditions leading to early triggering

Symptom
Job starts when one of two upstream jobs succeeds, even though both were expected before starting.
Fix
Use AND instead of OR if all dependencies are required. If OR is intended but the trigger happens too early, consider using a box to group the upstream jobs and condition on the box.
×

Assuming notrunning() waits for a job to run

Symptom
Job with condition: notrunning(resource_job) starts immediately because resource_job never ran and is INACTIVE.
Fix
Use success() or done() for sequential dependencies. Only use notrunning() when you specifically want to check runtime state.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What is the difference between success() and done() conditions in AutoSy...
Q02JUNIOR
What does the condition failure() do?
Q03SENIOR
Can an AutoSys job condition reference jobs in a different box?
Q04SENIOR
What happens if you have a circular dependency in AutoSys conditions?
Q05JUNIOR
What condition would you use for a cleanup job that must run whether or ...
Q06SENIOR
How does the notrunning() condition behave if the referenced job has nev...
Q01 of 06JUNIOR

What is the difference between success() and done() conditions in AutoSys?

ANSWER
success() triggers when the referenced job completes with exit code 0 (success). done() triggers when the reference job completes regardless of exit code. So done() runs even if the job failed, while success() only runs on success. Use success() for normal chaining and done() for cleanup or notification jobs that must always execute.
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
What conditions can I use in AutoSys?
02
What is the done() condition in AutoSys?
03
Can AutoSys job conditions span multiple boxes?
04
What happens if I create a circular dependency in AutoSys?
05
How do I make a job run after any one of several jobs succeeds?
06
What is the difference between notrunning() and success()?
COMPLETE GUIDE
The Complete AutoSys Workload Automation Guide for Engineers →

JIL syntax, sendevent, autorep, box jobs, file watchers, scheduling, HA, security, cloud workload automation, and 22 interview questions — the definitive AutoSys reference for production engineers.

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Drawn from code that ran under real load.

Follow
Verified
production tested
May 23, 2026
last updated
1,554
articles · all by Naren
🔥

That's AutoSys. Mark it forged?

7 min read · try the examples if you haven't

Previous
AutoSys Job Scheduling and Time Conditions
14 / 30 · AutoSys
Next
AutoSys Calendars and run_calendar