SaveMyCert
Log in
5 of 5 free questions left today·for 30 a day
Working with Lakeflow Jobs

Lakeflow Jobs Schedules and Triggers: Scheduled, File Arrival, Table Update and Continuous (Databricks Data Engineer Associate)

14 min readDatabricks DEA · Working with Lakeflow JobsUpdated

Lakeflow Jobs triggers decide when a job starts a run on its own: a scheduled trigger starts runs at set times, file arrival and table update triggers start them when new data lands in storage or in Unity Catalog tables, and a continuous trigger keeps one run always active. This lesson covers how to configure each trigger (simple and advanced schedules, Quartz cron, time zones, file arrival limits, Any vs All table conditions and the timing settings), the job settings that act on every trigger (maximum concurrent runs, queueing, pause and resume), the dynamic value references that tell a task why it ran, and how to choose between time-based and data-driven triggers from data availability and pipeline dependencies.

What you’ll learn
  • Choose between scheduled, file arrival, table update and continuous triggers from a job's data availability, deadlines and upstream dependencies
  • Configure simple and advanced schedules, write Quartz cron expressions, and pick UTC or a local time zone
  • Configure file arrival triggers, including new-file rules, recursive monitoring, Auto Loader ingestion and the limits without file events
  • Configure table update triggers with Any or All conditions, minimum time between triggers and wait after last change, and the run-as privileges they need
  • Explain how maximum concurrent runs, queueing, pause and resume affect triggered runs
  • Pass trigger dynamic value references such as job.trigger.type, updated_tables and version to tasks

Trigger types in Lakeflow Jobs

A trigger decides when Lakeflow Jobs starts a new run of a job without anyone clicking Run now. A job can be started manually at any time, and it can have one of these automatic triggers (multiple triggers per job are in Beta):

TriggerKindStarts a run whenTypical use
ScheduledTime-basedThe clock reaches the next scheduled timeFixed cut-offs, daily reports, sources that send no signal
File arrivalData-drivenNew files appear in a Unity Catalog volume or external locationFiles delivered at unpredictable times
Table updateData-drivenMonitored Unity Catalog tables, materialized views, streaming tables or views receive new dataDepending on a table another pipeline or team produces
ContinuousAlways onThe previous run ends (one run is always active)Always-on Structured Streaming workloads

The exam objective asks you to implement these triggers and to choose between time-based and data-driven ones. The rest of this lesson takes each trigger in turn, then the job settings that interact with every trigger (maximum concurrent runs, queueing, pause and resume), the dynamic value references that tell a task why it ran, and finally the decision itself. How tasks inside a run depend on each other, retry and branch is covered in the sibling lesson on tasks, dependencies and control flow.

Scheduled triggers: simple vs advanced schedules

A scheduled trigger starts runs on a time-based schedule, and it comes in two forms that differ in how much of the timing you control.

Simple scheduleAdvanced schedule
What you setA unit and an interval, such as every 12 hours or every 1 dayPeriod, start time and time zone, or a Quartz cron expression (Show cron syntax)
Who picks the clock timeDatabricks, when the schedule is savedYou
Stable across editsNo: saving the schedule again can move every later runYes: the start time and time zone are stored
Use it for"Roughly every N hours" where the exact time does not matter"07:40 Tokyo time", "noon on Saturdays", business-hour windows

The practical consequence: if a job must run at a particular wall-clock time, or downstream teams rely on the run times not changing, use an advanced schedule. Saving a simple schedule at the "right" moment is fragile, because the next edit and save moves the runs again.

Quartz cron syntax in advanced schedules

Advanced schedules accept Quartz cron expressions, which differ from the familiar Unix cron in two ways: they start with a seconds field, and one of the two day fields must be ? (no specific value).

PositionFieldExamples
1Seconds0
2Minutes30, 0/15 (every 15 minutes from :00)
3Hours2, 8-17
4Day of month*, 1, ?
5Month*
6Day of week?, MON-FRI

Reading a few expressions field by field:

  • 0 45 4 * * ? runs at 04:45:00 every day: seconds 0, minute 45, hour 4, any day of month, any month, no specific day of week.
  • 0 30 7 ? * SAT,SUN runs at 07:30 on Saturdays and Sundays. Day of week carries the value, so day of month is ?.
  • 0 0/10 9-16 * * ? runs every 10 minutes from 09:00 to 16:50 every day. An hours range covers every minute inside its last hour, so 9-16 ends with the 16:50 run and never reaches 17:00.

Because every field is positional, read each expression left to right as seconds, minutes, hours, day of month, month, day of week, and check three things: there are six fields (not Unix cron's five), the step or range sits in the field you meant, and exactly one of the two day fields is ?.

Time zones and daylight saving

The time zone of an advanced schedule decides which clock the schedule follows, and the right choice depends on whether the requirement is a fixed interval or a local clock time.

  • Fixed interval, every N minutes or hours, all year: use UTC. Databricks notes that an hourly job scheduled in a time zone that observes daylight saving can be skipped or appear delayed by an hour or two around the clock change. UTC has no clock change, so the period is always exact.
  • Fixed local time, such as 09:00 New York every weekday: use the local time zone (America/New_York). Any single UTC time is correct for only part of the year, because the offset from UTC changes with daylight saving.

Problems caused by the schedule itself are not fixed by job settings that act on runs: queueing, a higher concurrency limit or task retries cannot create a run the schedule never produced. Change the time zone instead.

File arrival triggers

A file arrival trigger starts a run when new files arrive in a monitored location: a path in a Unity Catalog volume or an external location. Databricks checks the location about once a minute, so the run starts shortly after a delivery and no run starts when nothing has arrived.

Rules that decide many scenarios:

  • Only new files count. Overwriting an existing file with the same name does not trigger a run. A partner that replaces inventory.json in place each night triggers the job only once, when that file name first appeared. Every delivery needs its own file name (for example one that includes a timestamp) to count as an arrival.
  • Subdirectories are checked recursively. One trigger on a landing folder sees files in every dated subfolder below it, including subfolders created later, so there is no need to add a trigger per day or per year.
  • The trigger does not tell the job which files are new. The only file arrival dynamic value reference is the monitored location. Several files can be batched into one run and others can land while a run is in progress, so filtering by time misses files and reading the whole path duplicates them. The documented pattern is to have the job read the path with Auto Loader using trigger(availableNow=True) and a checkpoint: it loads every file not yet recorded in the checkpoint, then stops, giving exactly-once loading across batched arrivals and retried runs.

Limits without file events

When the external location is not enabled for file events, the trigger has to list the storage itself, and two limits apply:

  • The monitored path can hold at most 10,000 files. The limit applies to the path the trigger monitors, including its subdirectories, not to the whole external location, so pointing the trigger at a smaller subfolder (for example an incoming folder rather than a parent that also contains an archive) can bring it under the limit.
  • A workspace can have at most 50 jobs with file arrival triggers on locations without file events.

Databricks recommends enabling managed file events on the external location. Triggers on a location with file events have no file-count limit and do not count toward the 50-job limit. Enabling file events requires the owner of the external location or the MANAGE privilege on it. Timing settings do nothing for either limit.

Timing settings: minimum time between triggers vs wait after last change

File arrival and table update triggers share two optional advanced settings, and they solve different problems: one caps how often runs start, the other waits for a quiet period before starting.

SettingWhat it doesSolvesPitfall
Minimum time between triggersNo new run starts until this long after the previous run completedCost caps: "at most one run per 30 minutes" while still reacting to changesDoes not delay the first run of a burst, so a run can still start on a partial delivery
Wait after last changeA run starts only after no new file or table update has arrived for this long; every new change resets the timerBursts: many files over several minutes become one run after the burst endsOn a source that changes continuously, the location is never quiet long enough, so runs are postponed until it stops

When both are set, a run starts at the later of the two conditions. Work an example: the previous run completed at time 0, minimum time between triggers is 600 seconds and wait after last change is 120 seconds. Updates arrive at 100 and 550 seconds. Nothing can start before 600 seconds, and the quiet period ends 120 seconds after the last update, at 670 seconds, so the run starts at 670 seconds.

Two requirements usually mean two settings: a cost cap needs the minimum time, "do not start in the middle of a burst" needs a short wait. Size the wait to the gap between changes within one delivery, not to the gap between deliveries: a wait longer than the usual gap between changes keeps postponing the run on a busy source.

Table update triggers

A table update trigger starts a run when one or more monitored objects receive new data. It reads the objects' metadata and change history, so the job follows the data without being wired into the producer's job. Supported objects are Unity Catalog tables (managed and external Delta tables, and managed Iceberg tables), materialized views, streaming tables, views and metric views built on them. A view that uses read_files, or depends on tables outside Unity Catalog or on federated tables, is not supported: the trigger can be saved but never fires. This is the trigger for "start when another team's table has been refreshed", at times that team controls and does not publish, without changing their pipeline.

Any vs All

With several monitored tables, the Trigger when condition decides how they combine:

ConditionStarts a run whenUse it when
Any table is updatedAny one monitored table changesEach source should be processed as soon as it changes, without waiting for the others
All tables are updatedEvery monitored table has changed since the last runThe job joins the sources and must never run on a partly refreshed set

The cost of All: it waits for every monitored table, so any table in the list that no longer changes means the condition can never be met and the job stops running. Only tables that are expected to keep changing belong in an All condition.

Views count every change to their base tables

For a monitored view, any update to a table the view depends on counts as an update to the view, even when the view's result does not change. A view selecting country = 'DE' from a shipments table that receives frequent rows for other countries therefore triggers on every one of those writes. If runs must follow German shipments only, use a source that changes only with EU data or have the job check for new rows and exit early.

Run-as permissions

The trigger is evaluated as the job's Run as principal, which needs SELECT on every monitored object plus USE CATALOG and USE SCHEMA on its parents. For a monitored view it also needs SELECT on the view's underlying tables, even if it can query the view through the view owner's access. Without these privileges the trigger cannot evaluate and the job never runs, which shows up as an empty run history rather than failed runs. Write privileges, job permissions and BROWSE do not help.

The timing settings in the previous section apply to table update triggers too; the minimum time is counted from the completion of the previous run.

Continuous jobs

A continuous trigger keeps a job always running: exactly one run is active at a time, and a new run starts shortly after the previous one ends. Databricks recommends it for always-on Structured Streaming workloads, replacing the older pattern of a manually started job with unlimited retries and one concurrent run.

  • Failure handling is at the job level. When runs fail repeatedly, Databricks waits longer between restarts (exponential backoff). You do not configure task retries for this.
  • No task dependencies. A continuous job cannot have tasks linked with Depends on. For a bronze, silver and gold chain of streaming notebooks this is fine: each streams from the table above it, so the tasks can run in parallel; with dependencies the downstream tasks would wait forever, because an upstream stream never completes.
  • Not combined with other triggers. A continuous job does not also have a schedule, file arrival or table update trigger.
  • Serverless compute: only bounded Structured Streaming triggers such as trigger(availableNow=True) are supported in continuous jobs; time-based stream triggers (processingTime, continuous processing) are not. Each run processes what is available and ends, the continuous trigger starts the next run, and the checkpoint keeps processing exactly once.

Continuous mode suits work that must never stop. It is the wrong choice for a job that should run only when something changed, or once at a fixed time, because it reruns regardless.

Maximum concurrent runs, queueing, and pausing

Every trigger hands its runs to the same job-level controls, and they decide what happens when a run is due while another is still active.

  • Maximum concurrent runs defaults to 1 for new jobs. A new run that would exceed the limit is skipped when queueing is off: it appears with a Skipped state (the Jobs API reports MAX_CONCURRENT_RUNS_EXCEEDED), and no task failed.
  • Queueing, when turned on, holds such a run in a queue for up to 48 hours and starts it when capacity frees up. Runs are never merged. Queueing is on by default for jobs created in the UI after 15 April 2024, which is why an overrun on a newer job usually shows a queued run rather than a skipped one.
ConfigurationRuns overlap?Runs dropped when one overruns?
Concurrency 1, queueing offNoYes, skipped
Concurrency 1, queueing onNoNo, queued then started
Concurrency 2 or moreYesNot until the higher limit is reached

A queued run starts late, so anything that names output by "now" drifts; see the trigger time reference below.

Pause and resume

Pausing a trigger stops it from creating new runs while keeping its configuration; runs already in progress finish, and Resume restores the same schedule or condition. Manual runs keep working while a trigger is paused: Run now on a paused continuous job produces a single run, and the job stays paused once it finishes. Deleting the trigger instead loses its configuration, and lowering the concurrency limit to stop runs affects manual runs as well.

Dynamic value references for triggers

Dynamic value references pass facts about the run into task parameters, and the trigger references tell the code why and on what the run started.

ReferenceResolves toTypical use
{{job.trigger.type}}What started the run, such as periodic (schedule), one_time (Run now), file_arrival, table, continuous, run_job_taskSuppress side effects, such as posting to a team chat channel, when the run was not scheduled
{{job.trigger.time.iso_datetime}}When the run was triggered, in UTC; for cron schedules rounded down to the minuteNaming the scheduled slot (partition) even when the run starts late from the queue
{{job.start_time.iso_datetime}}When the run actually startedMeasuring when work happened, not which slot it belongs to
{{job.trigger.file_arrival.location}}The monitored file location (not a list of new files)Passing the path to Auto Loader
{{job.trigger.table_update.updated_tables}}A JSON list of the monitored tables that changed since the last runRebuilding only the outputs whose sources changed
{{job.trigger.table_update.version}}For a single monitored table, the latest commit version that triggered the runBounding a change data feed read with endingVersion
{{job.trigger.table_update.commit_timestamp.iso_datetime}}For a single monitored table, the timestamp of that commitBounding a read by time (endingTimestamp)

The distinction between trigger time and start time matters with queueing: a daily run due at 23:50 that waits in the queue for 20 minutes still has the trigger time of its scheduled day, while its start time and any current_timestamp() in the code fall on the next day.

Choosing time-based or data-driven triggers

Choose a data-driven trigger when the job should follow the data's availability, and a scheduled trigger when the requirement is a point in time or there is nothing to observe. The questions to ask:

  1. Is there a fixed cut-off or deadline? "One report at 06:00 from whatever has arrived" or "one report per weekday from the data as of 06:00" is time-based. Data-driven triggers would fire too early, several times, or never when one input is missing; late data simply goes into the next scheduled run.
  2. Does the data arrive at unpredictable times, and should the job react promptly without wasting runs? Files in a volume or external location: file arrival. A table refreshed by another pipeline or team: table update. A schedule guessed from usual refresh times either runs before the data (and builds from stale data on late days) or adds delay on normal days.
  3. Is there anything to observe? A job that fetches exchange rates from an external web service produces no files or upstream table changes for Databricks to watch, and a table update trigger on the table the job writes would wait for the job itself. When the source sends no signal, use a schedule.
  4. Must it never stop? Always-on streaming: continuous.

Pipeline dependencies decide the configuration of a data-driven trigger: depend on the table you actually read (not on the producer's input files, which fire before the table is built), use All when every input must be fresh and Any when each change matters on its own, and add the timing settings for cost caps and bursts.

Tip. Expect scenarios describing a job, how its data arrives and what the business needs: a fixed report time, prompt processing of files or table refreshes at unpredictable times, always-on streaming, a cost cap or one run per delivery. Items ask which trigger to use, which advanced setting meets a timing requirement, which Quartz cron expression or time zone is correct, why a trigger never fires or a run was skipped (overwritten files, file-count limits, missing privileges, an All condition that cannot be met, concurrency), how Any and All combine monitored tables, and which dynamic value reference a task needs. Several items offer two workable configurations where one stated constraint decides.

Key takeaways
  • Scheduled triggers are time-based; file arrival and table update triggers are data-driven; a continuous trigger keeps exactly one run active.
  • A simple schedule sets only a unit and interval and Databricks picks the clock time when it is saved; use an advanced schedule for a fixed start time and time zone.
  • Quartz cron starts with a seconds field and needs ? in either day of month or day of week.
  • Use UTC for a true fixed interval all year; use the local time zone for a fixed local clock time.
  • File arrival triggers fire on new files only (not overwrites), check subfolders recursively and do not pass a file list; read the path with Auto Loader and availableNow.
  • Without file events, a monitored path is limited to 10,000 files and a workspace to 50 such jobs; enabling managed file events removes both limits.
  • Minimum time between triggers caps run frequency; wait after last change waits for a quiet period and resets on every change.
  • Table update triggers use Any or All across monitored tables, count every base-table change for a monitored view, and need SELECT plus USE CATALOG and USE SCHEMA for the run-as principal.
  • With maximum concurrent runs reached, a run is skipped unless queueing is on, which holds it for up to 48 hours.
  • Pausing a trigger keeps its configuration and still allows Run now.

Frequently asked questions

What is the difference between a file arrival trigger and a table update trigger in Lakeflow Jobs?

A file arrival trigger starts a job when new files land in a Unity Catalog volume or external location, and suits raw files delivered at unpredictable times. A table update trigger starts a job when monitored Unity Catalog tables, materialized views, streaming tables or views receive new data, and suits depending on a table that another pipeline produces. Use the trigger that watches the thing the job actually reads.

Why did my file arrival trigger stop firing when the file changes every day?

File arrival triggers start runs only for new files. Overwriting an existing file with the same name does not count as an arrival, so a job watching a file that is rewritten in place runs once, when the file first appears. Giving each delivery its own file name makes every delivery a new arrival.

What is the difference between minimum time between triggers and wait after last change?

Minimum time between triggers stops a new run from starting until a set time after the previous run completed, so it caps how often a job runs. Wait after last change starts a run only after no new files or table updates have arrived for a set time, and each change resets the timer, so it turns a burst of arrivals into one run after the burst ends. When both are set, the run starts once both conditions are met.

Should a Lakeflow Jobs schedule use UTC or a local time zone?

Use UTC when the job needs a true fixed interval, such as every hour all year, because an hourly job in a daylight-saving time zone can be skipped or appear delayed by an hour or two around the clock change. Use the local time zone when the job must start at a fixed local time, such as 09:00 in New York, because a single UTC time is an hour off for part of the year.

What happens when a scheduled run is due while the previous run is still active?

New jobs default to a maximum of one concurrent run. If queueing is off, the new run is skipped and recorded with a Skipped state. If queueing is on, the run waits in a queue for up to 48 hours and starts when the active run finishes. Queueing is on by default for jobs created in the UI after 15 April 2024.

Why does a table update trigger never start my job even though the table changes?

The trigger is evaluated as the job's Run as principal, which needs SELECT on each monitored object plus USE CATALOG and USE SCHEMA on its parents, and SELECT on the underlying tables of a monitored view. Without that access the trigger cannot evaluate and the job does not run. Another cause is an All tables are updated condition that includes a monitored table which no longer changes, or a monitored view that uses read_files or non-Unity Catalog tables, which is unsupported.

Can a continuous job have task dependencies?

No. A continuous job cannot have tasks linked with Depends on, and it cannot be combined with other trigger types. Streaming tasks that each read the table above them can run in parallel in one continuous job, and repeated failures are retried at the job level with increasing waits.

Source

This lesson covers the "Working with Lakeflow Jobs" domain of the official Databricks DEA exam guide. Vendors revise their guides — check the source for the current version.

Test yourself on this topic
Practice now

Sign up free to mark lessons complete, bookmark topics and track your exam readiness.

Spotted a mistake in this lesson?