Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .nextchanges/bundles/job-runs-on-value-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* direct: `resources.job_runs` can set `lifecycle.triggers.on_value_change` to an interpolated expression (for example `${resources.jobs.foo.id}`) to re-fire the run when that resolved value changes or a watch is added. Resolved values are recorded as SHA-256 hashes; removing a watch leaves the run in place. ([#6341](https://github.com/databricks/cli/pull/6341))
3 changes: 3 additions & 0 deletions acceptance/bundle/refschema/out.fields.txt
Original file line number Diff line number Diff line change
Expand Up @@ -929,10 +929,13 @@ resources.job_runs.*.lifecycle.triggers []resources.JobRunTrigger INPUT
resources.job_runs.*.lifecycle.triggers[*] resources.JobRunTrigger INPUT
resources.job_runs.*.lifecycle.triggers[*].on_bundle_deploy *bool INPUT
resources.job_runs.*.lifecycle.triggers[*].on_file_change *string INPUT
resources.job_runs.*.lifecycle.triggers[*].on_value_change *string INPUT
resources.job_runs.*.lifecycle.triggers_state *resources.JobRunTriggersState INPUT STATE
resources.job_runs.*.lifecycle.triggers_state.on_bundle_deploy string INPUT STATE
resources.job_runs.*.lifecycle.triggers_state.on_file_change map[string]string INPUT STATE
resources.job_runs.*.lifecycle.triggers_state.on_file_change.* string INPUT STATE
resources.job_runs.*.lifecycle.triggers_state.on_value_change map[string]string INPUT STATE
resources.job_runs.*.lifecycle.triggers_state.on_value_change.* string INPUT STATE
resources.job_runs.*.modified_status string INPUT
resources.job_runs.*.notebook_params map[string]string ALL
resources.job_runs.*.notebook_params.* string ALL
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
bundle:
name: job-runs-on-value-change

variables:
stamp:
default: v1
other:
default: a1
number:
default: 42
long:
default: a-long-non-hex-watched-value-used-to-exercise-a-lengthy-string-zzz

resources:
jobs:
my_job:
name: my-job
tasks:
- task_key: main
notebook_task:
notebook_path: /Workspace/test

job_runs:
my_run:
job_id: ${resources.jobs.my_job.id}
lifecycle:
triggers:
- on_file_change: watched.txt
- on_value_change: " ${var.stamp} "
- on_value_change: ${var.other}
- on_value_change: ${var.number}
- on_value_change: ${workspace.root_path}
- on_value_change: ${var.long}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

261 changes: 261 additions & 0 deletions acceptance/bundle/resources/job_runs/on_value_change/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@

=== first deploy triggers a run
>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/job-runs-on-value-change/default/files...
Output from job_runs.my_run: id=[MY_RUN_ID]: Run URL: [DATABRICKS_URL]/jobs/[MY_JOB_ID]/runs/[MY_RUN_ID]?o=[NUMID]
Output from job_runs.my_run: id=[MY_RUN_ID]: SUCCESS
Created job_runs.my_run
Created jobs.my_job
Files: 4 uploaded, 0 deleted
Resources: 2 created, 0 changed, 0 deleted, 0 unchanged

>>> read_id.py my_job
[MY_JOB_ID]

>>> print_requests.py //jobs/run-now
{
"method": "POST",
"path": "/api/2.2/jobs/run-now",
"body": {
"idempotency_token": "[UUID]",
"job_id": [MY_JOB_ID]
}
}

=== resolved values are stored as hashes
>>> print_state.py
{
"on_file_change": {
"watched.txt": "[FILE_HASH][0]"
},
"on_value_change": {
"${var.long}": "a-long-non-hex-watched-value-used-to-exercise-a-lengthy-string-zzz",
"${var.number}": "42",
"${var.other}": "a1",
"${var.stamp}": "v1",
"${workspace.root_path}": "/Workspace/Users/[USERNAME]/.bundle/job-runs-on-value-change/default"
}
}

=== redeploy with unchanged values plans nothing
>>> [CLI] bundle plan
Plan: 0 to add, 0 to change, 0 to delete, 2 unchanged

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/job-runs-on-value-change/default/files...
Files: 0 uploaded, 0 deleted
Resources: 0 created, 0 changed, 0 deleted, 2 unchanged

>>> print_requests.py //jobs/run-now

=== changing one value re-fires
>>> [CLI] bundle plan
recreate job_runs.my_run

Plan: 1 to add, 0 to change, 1 to delete, 1 unchanged

>>> changes
{
"lifecycle.triggers_state.on_value_change['${var.stamp}']": {
"action": "recreate",
"reason": "immutable",
"old": "v1",
"new": "v2"
},
"result_state": {
"action": "skip",
"reason": "remote_already_set",
"new": "SUCCESS",
"remote": "SUCCESS"
}
}

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/job-runs-on-value-change/default/files...
Output from job_runs.my_run: id=[MY_RUN_ID_2]: Run URL: [DATABRICKS_URL]/jobs/[MY_JOB_ID]/runs/[MY_RUN_ID_2]?o=[NUMID]
Output from job_runs.my_run: id=[MY_RUN_ID_2]: SUCCESS
Recreated job_runs.my_run
Files: 1 uploaded, 0 deleted
Resources: 1 created, 0 changed, 1 deleted, 1 unchanged

>>> print_requests.py --keep //jobs/runs/delete
{
"method": "POST",
"path": "/api/2.2/jobs/runs/delete",
"body": {
"run_id": [MY_RUN_ID]
}
}

>>> print_requests.py //jobs/run-now
{
"method": "POST",
"path": "/api/2.2/jobs/run-now",
"body": {
"idempotency_token": "[UUID]",
"job_id": [MY_JOB_ID]
}
}

=== removing one on_value_change through a saved plan does not run
>>> [CLI] bundle plan
Plan: 0 to add, 0 to change, 0 to delete, 2 unchanged

>>> [CLI] bundle deploy --plan tmp.plan.json
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/job-runs-on-value-change/default/files...
Files: 2 uploaded, 0 deleted
Resources: 0 created, 0 changed, 0 deleted, 2 unchanged

>>> print_requests.py //jobs/run-now

=== re-adding the same on_value_change after the saved plan re-fires
>>> [CLI] bundle plan
Plan: 0 to add, 0 to change, 0 to delete, 2 unchanged

>>> changes
{
"result_state": {
"action": "skip",
"reason": "remote_already_set",
"new": "SUCCESS",
"remote": "SUCCESS"
}
}

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/job-runs-on-value-change/default/files...
Files: 1 uploaded, 0 deleted
Resources: 0 created, 0 changed, 0 deleted, 2 unchanged

>>> print_requests.py --keep //jobs/runs/delete

>>> print_requests.py //jobs/run-now

=== removing the same on_value_change again does not run
>>> [CLI] bundle plan
Plan: 0 to add, 0 to change, 0 to delete, 2 unchanged

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/job-runs-on-value-change/default/files...
Files: 1 uploaded, 0 deleted
Resources: 0 created, 0 changed, 0 deleted, 2 unchanged

>>> print_requests.py //jobs/run-now

=== changing a remaining watch to a removed value re-fires
>>> [CLI] bundle plan
recreate job_runs.my_run

Plan: 1 to add, 0 to change, 1 to delete, 1 unchanged

>>> changes
{
"lifecycle.triggers_state.on_value_change['${var.stamp}']": {
"action": "recreate",
"reason": "immutable",
"old": "v2",
"new": "a1"
},
"result_state": {
"action": "skip",
"reason": "remote_already_set",
"new": "SUCCESS",
"remote": "SUCCESS"
}
}

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/job-runs-on-value-change/default/files...
Output from job_runs.my_run: id=[MY_RUN_ID_4]: Run URL: [DATABRICKS_URL]/jobs/[MY_JOB_ID]/runs/[MY_RUN_ID_4]?o=[NUMID]
Output from job_runs.my_run: id=[MY_RUN_ID_4]: SUCCESS
Recreated job_runs.my_run
Files: 1 uploaded, 0 deleted
Resources: 1 created, 0 changed, 1 deleted, 1 unchanged

>>> print_requests.py --keep //jobs/runs/delete
{
"method": "POST",
"path": "/api/2.2/jobs/runs/delete",
"body": {
"run_id": [MY_RUN_ID_2]
}
}

>>> print_requests.py //jobs/run-now
{
"method": "POST",
"path": "/api/2.2/jobs/run-now",
"body": {
"idempotency_token": "[UUID]",
"job_id": [MY_JOB_ID]
}
}

=== removing the remaining on_value_change entries is unchanged and does not run
>>> [CLI] bundle plan
Plan: 0 to add, 0 to change, 0 to delete, 2 unchanged

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/job-runs-on-value-change/default/files...
Files: 1 uploaded, 0 deleted
Resources: 0 created, 0 changed, 0 deleted, 2 unchanged

>>> print_requests.py //jobs/run-now

=== file changes still re-fire after value triggers are removed
>>> [CLI] bundle plan
recreate job_runs.my_run

Plan: 1 to add, 0 to change, 1 to delete, 1 unchanged

>>> changes
{
"lifecycle.triggers_state.on_file_change['watched.txt']": {
"action": "recreate",
"reason": "immutable",
"old": "[FILE_HASH][0]",
"new": "[FILE_HASH][1]"
},
"result_state": {
"action": "skip",
"reason": "remote_already_set",
"new": "SUCCESS",
"remote": "SUCCESS"
}
}

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/job-runs-on-value-change/default/files...
Output from job_runs.my_run: id=[MY_RUN_ID_5]: Run URL: [DATABRICKS_URL]/jobs/[MY_JOB_ID]/runs/[MY_RUN_ID_5]?o=[NUMID]
Output from job_runs.my_run: id=[MY_RUN_ID_5]: SUCCESS
Recreated job_runs.my_run
Files: 1 uploaded, 0 deleted
Resources: 1 created, 0 changed, 1 deleted, 1 unchanged

>>> print_requests.py --keep //jobs/runs/delete
{
"method": "POST",
"path": "/api/2.2/jobs/runs/delete",
"body": {
"run_id": [MY_RUN_ID_4]
}
}

>>> print_requests.py //jobs/run-now
{
"method": "POST",
"path": "/api/2.2/jobs/run-now",
"body": {
"idempotency_token": "[UUID]",
"job_id": [MY_JOB_ID]
}
}

>>> [CLI] bundle destroy --auto-approve
The following resources will be deleted:
delete resources.job_runs.my_run
delete resources.jobs.my_job

All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/job-runs-on-value-change/default

Destroy: 2 deleted
Loading
Loading