Skip to content

Retry the deploy lock create after transient errors - #7594

Open
denik wants to merge 9 commits into
mainfrom
denik/retry-lock-create
Open

denik wants to merge 9 commits into
mainfrom
denik/retry-lock-create

Conversation

@denik

@denik denik commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Changes

  • Locker.Lock now retries the lock create (import-file with overwrite=false) on the errors libs/retry.IsTransientRead covers: 5xx/408 that the SDK did not retry, the SDK's inactivity timeout ("request timed out after ... of inactivity"), and a connection cut mid-response (unexpected EOF, REFUSED_STREAM). That check is named for reads, but the lock create is safe to repeat for the reason below, so it gets the same coverage. Forced locks overwrite and were already retried by retry.Filer (on retry.IsTransient, which does not include unexpected EOF), so their write is unchanged; they do get the read-back below. Retrying overwrites on unexpected EOF is left to #7611.
  • When the last attempt still fails with a transient error, forced or not, Lock reads the lock back. If that attempt was applied and the lock is ours, the lock is taken; otherwise it would stay behind, and nobody would release it. If the lock belongs to someone else, the error names the holder ("deploy lock acquired by ..."), except with --force-lock, where that message would suggest the flag already in use, so the write error is returned instead. If there is no lock, or the read fails too, the original error is returned.
  • acceptance/bundle/telemetry/deploy-failed-engine-unknown stubs every import-file with a 500, which now hits the lock-create retries; it sets DATABRICKS_BUNDLE_RETRY_INTERVAL_MS like the other tests that inject 5xx, so it does not sleep 30s.
  • New acceptance test bundle/deploy/lock-retry injects 504s on the lock create and covers these cases:
    • the create was applied before the 504: the retry hits 409 and the lock turns out to be ours;
    • the create was not applied: the retry creates the lock;
    • every attempt returns a 504, but the first one was applied: the read-back finds our lock;
    • another deployer already holds the lock: the retry hits 409 and the error names the holder.
    • another deployer holds the lock and every attempt returns a 504: the read-back names the holder;
    • --force-lock and every overwrite attempt returns a 504 but is applied: the read-back finds our lock.
    • --force-lock over another deployer's lock, and every overwrite attempt returns a 504 without being applied: the error is the 504.
  • Unit tests in libs/locker for unexpected EOF on the lock create: not applied, applied before the cut, retries exhausted but the last attempt applied, and every attempt failing. fault.py cannot cut a connection, so this case has no acceptance test.
  • New acceptance test bundle/deploy/lock-timeout: every lock create stalls past the inactivity timeout, so the CLI makes three attempts, finds no lock when it reads it back, and fails with the timeout.
  • Changelog entry in .nextchanges/bundles/lock-retry.md.

Why

#7521 made workspace calls retry after the SDK's inactivity timeout, but it deliberately skipped writes that do not overwrite, because a repeated create could fail on the file its own earlier attempt created. The deploy lock create is one of those writes, so the same server-side stalls still fail deploys at "Failed to acquire deployment lock". The failures below all ran on a main commit that already includes #7521.

Retrying this create is safe because of how the lock works: the lock file holds the locker's unique ID, and Lock always reads the file back (assertLockHeld) after a create that fails with "already exists". So whatever the earlier attempt did, the retry ends in a correct state:

  • the earlier attempt created the file: the retry gets 409, the read-back finds our ID, and we hold the lock;
  • it did not: the retry creates the file;
  • another deployer took the lock in between: the retry gets 409, the read-back finds their ID, and we fail with the usual "deploy lock acquired by ..." error.

A late-arriving earlier attempt cannot overwrite anything either, since it also uses overwrite=false.

Known edge case, which the 504 retries elsewhere share: after an inactivity timeout the server might still apply the stalled request later. If it does so only after this deploy has released the lock, the late create leaves a stale lock carrying our ID, and the next deploy needs --force-lock. A stale lock from a single timed-out create was already possible before this change.

Not done: an opt-in in retry.Filer for "fs.ErrExist after a retry is fine". Only the lock needs it today, and it is safe there only because of the read-back, so I kept the logic in Lock.

Judgment call: I used the same retry budget as #7521 (MaxRetries = 2, 15s pause) so the lock acts like the other workspace writes. A persistent write stall now takes about 5 minutes (3 × 90s + 2 × 15s) before the deploy fails, which matches #7521. If reads stall too, the read-back after the last attempt is retried the same way through retry.Filer, so the worst case is about 10 minutes. I kept the retried read: a single read gives up on the first stall, which more often leaves an applied lock of ours behind for nobody to release.

Tests

  • acceptance/bundle/deploy/lock-retry and lock-timeout (local testserver, both DMS variants). Without the change, it fails with Error: Failed to acquire deployment lock: Fault injected by test.
  • Ran the local bundle/deploy, bundle/destroy, bundle/upload, bundle/state and pipelines deploy/destroy acceptance tests. The only failures are bundle/state/state_present and bundle/state/engine_default, which fail on main too on my machine: they record the user agent, which picks up an extra agent-environment token there.
  • I did not add a cloud test: the stalls are random and server-side, so a cloud run cannot trigger them on demand. The timeout classification is already unit-tested in libs/retry.

Dashboard:

error snippet
error/124 Error: Failed to acquire deployment lock: Post "[DATABRICKS_URL]/api/2.0/workspace-files/import-file/Workspace%2FUsers%2F[USERNAME]%2F.bundle%2F...%2Fdefault%2Fstate%2Fdeploy.lock?overwrite=false": request timed out after 1m30s of inactivity
error/125 Error: Failed to acquire deployment lock: Post "[DATABRICKS_URL]/api/2.0/workspace-files/import-file/[PATH]": unexpected EOF

On main in the last 2 days: 13 failures on 11 tests (AWS, Azure, GCP), e.g. TestAccept/bundle/resources/postgres_branches/recreate/DMS= and TestAccept/bundle/resources/grants/feature_specs/DMS=.

This pull request and its description were written by Isaac.

The lock create (import-file with overwrite=false) was the one workspace
write left out of the retries added in #7521, so an inactivity timeout
or a 5xx on it still failed the deploy. Retrying it is safe: the lock
file carries the locker's unique ID, so if an earlier attempt did create
the file, the retry gets a conflict and assertLockHeld confirms the lock
is ours.

Co-authored-by: Isaac <no-reply@databricks.com>
@denik denik added the ai-auto PRs made by AI loops & factories, label Nov 13, 2026
Co-authored-by: Isaac <no-reply@databricks.com>
@github-actions github-actions Bot added the DABs DABs related issues label Nov 13, 2026
@github-actions

github-actions Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Commit: f440de21f | Workflow run

Regression test report

Selected 3 changed tests (limit=20, 0 not selected)

5 tests: regression=4 unreleased=0 coverage=1 failing=0
test branch main (2699068) latest (v1.26.0)
TestAccept/bundle/deploy/lock-retry/DMS= ✅ ❌ ❌
TestAccept/bundle/deploy/lock-retry/DMS=true ✅ ❌ ❌
TestAccept/bundle/deploy/lock-timeout/DMS= ✅ ❌ ❌
TestAccept/bundle/deploy/lock-timeout/DMS=true ✅ ❌ ❌
TestAccept/bundle/telemetry/deploy-failed-engine-unknown/DMS= ✅ ✅ ✅
TestAccept/bundle/deploy/lock-retry/DMS=: branch ✅ | main (2699068) ❌ | latest (v1.26.0) ❌

main (2699068):

acceptance_test.go:1374: Diff:
        --- bundle/deploy/lock-retry/output.txt
        +++ /tmp/TestAcceptbundledeploylock-retryDMS=3489589530/002/output.txt
        @@ -2,94 +2,13 @@
         === Lock create is applied, but the response is a 504: the retry finds our own lock
         
         >>> [CLI] bundle deploy
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files...
        -Files: 0 uploaded, 0 deleted
        -Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
        -["POST","false"]
        -["POST","false"]
        -
        -=== Lock create is not applied and fails with a 504: the retry creates the lock
        -
        ->>> [CLI] bundle deploy
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files...
        -Files: 0 uploaded, 0 deleted
        -Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
        -["POST","false"]
        -["POST","false"]
        -
        -=== Every attempt returns a 504, but the first one is applied: reading the lock back finds it is ours
        -
        ->>> [CLI] bundle deploy
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files...
        -Files: 0 uploaded, 0 deleted
        -Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
        -["POST","false"]
        -["POST","false"]
        -["POST","false"]
        -
        -=== Lock is held by another deployer: the retry gets a conflict and the error names the holder
        -
        ->>> [CLI] bundle deploy
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Error: Failed to acquire deployment lock: deploy lock acquired by someone-else at [TIMESTAMP] +0000 UTC.
        -Another deployment may be in progress. Use --force-lock to override, but this may
        -conflict with the other deployment if it is still active
        -Error: deploy lock acquired by someone-else at [TIMESTAMP] +0000 UTC.
        -Another deployment may be in progress. Use --force-lock to override, but this may
        -conflict with the other deployment if it is still active
        -
        -
        -Exit code: 1
        -
        -=== Lock is held by another deployer and every attempt returns a 504: reading the lock back names the holder
        -
        ->>> [CLI] bundle deploy
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Error: Failed to acquire deployment lock: deploy lock acquired by someone-else at [TIMESTAMP] +0000 UTC.
        -Another deployment may be in progress. Use --force-lock to override, but this may
        -conflict with the other deployment if it is still active
        -Error: deploy lock acquired by someone-else at [TIMESTAMP] +0000 UTC.
        -Another deployment may be in progress. Use --force-lock to override, but this may
        -conflict with the other deployment if it is still active
        -
        -
        -Exit code: 1
        -["POST","false"]
        -["POST","false"]
        -["POST","false"]
        -
        -=== Forced lock, every overwrite attempt returns a 504 but is applied: reading the lock back finds it is ours
        -
        ->>> [CLI] bundle deploy --force-lock
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files...
        -Files: 0 uploaded, 0 deleted
        -Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
        -["POST","true"]
        -["POST","true"]
        -["POST","true"]
        -
        -=== Forced lock over another deployer's lock, every overwrite attempt returns a 504 and is not applied: the error is the 504
        -
        ->>> [CLI] bundle deploy --force-lock
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
         Error: Failed to acquire deployment lock: Fault injected by test.
         Error: Fault injected by test. (504 INJECTED)
         
        -Endpoint: POST [DATABRICKS_URL]/api/2.0/workspace-files/import-file/Workspace%2FUsers%2F[USERNAME]%2F.bundle%2Ftest-bundle%2Fdefault%2Fstate%2Fdeploy.lock?overwrite=true
        +Endpoint: POST [DATABRICKS_URL]/api/2.0/workspace-files/import-file/Workspace%2FUsers%2F[USERNAME]%2F.bundle%2Ftest-bundle%2Fdefault%2Fstate%2Fdeploy.lock?overwrite=false
         HTTP Status: 504 Gateway Timeout
         API error_code: INJECTED
         API message: Fault injected by test.
         
         
         Exit code: 1
        -["POST","true"]
        -["POST","true"]
        -["POST","true"]

latest (v1.26.0): same output as main (2699068)

TestAccept/bundle/deploy/lock-retry/DMS=true: branch ✅ | main (2699068) ❌ | latest (v1.26.0) ❌

main (2699068):

acceptance_test.go:1374: Diff:
        --- bundle/deploy/lock-retry/output.txt
        +++ /tmp/TestAcceptbundledeploylock-retryDMS=true2349756785/002/output.txt
        @@ -2,94 +2,13 @@
         === Lock create is applied, but the response is a 504: the retry finds our own lock
         
         >>> [CLI] bundle deploy
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files...
        -Files: 0 uploaded, 0 deleted
        -Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
        -["POST","false"]
        -["POST","false"]
        -
        -=== Lock create is not applied and fails with a 504: the retry creates the lock
        -
        ->>> [CLI] bundle deploy
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files...
        -Files: 0 uploaded, 0 deleted
        -Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
        -["POST","false"]
        -["POST","false"]
        -
        -=== Every attempt returns a 504, but the first one is applied: reading the lock back finds it is ours
        -
        ->>> [CLI] bundle deploy
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files...
        -Files: 0 uploaded, 0 deleted
        -Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
        -["POST","false"]
        -["POST","false"]
        -["POST","false"]
        -
        -=== Lock is held by another deployer: the retry gets a conflict and the error names the holder
        -
        ->>> [CLI] bundle deploy
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Error: Failed to acquire deployment lock: deploy lock acquired by someone-else at [TIMESTAMP] +0000 UTC.
        -Another deployment may be in progress. Use --force-lock to override, but this may
        -conflict with the other deployment if it is still active
        -Error: deploy lock acquired by someone-else at [TIMESTAMP] +0000 UTC.
        -Another deployment may be in progress. Use --force-lock to override, but this may
        -conflict with the other deployment if it is still active
        -
        -
        -Exit code: 1
        -
        -=== Lock is held by another deployer and every attempt returns a 504: reading the lock back names the holder
        -
        ->>> [CLI] bundle deploy
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Error: Failed to acquire deployment lock: deploy lock acquired by someone-else at [TIMESTAMP] +0000 UTC.
        -Another deployment may be in progress. Use --force-lock to override, but this may
        -conflict with the other deployment if it is still active
        -Error: deploy lock acquired by someone-else at [TIMESTAMP] +0000 UTC.
        -Another deployment may be in progress. Use --force-lock to override, but this may
        -conflict with the other deployment if it is still active
        -
        -
        -Exit code: 1
        -["POST","false"]
        -["POST","false"]
        -["POST","false"]
        -
        -=== Forced lock, every overwrite attempt returns a 504 but is applied: reading the lock back finds it is ours
        -
        ->>> [CLI] bundle deploy --force-lock
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files...
        -Files: 0 uploaded, 0 deleted
        -Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
        -["POST","true"]
        -["POST","true"]
        -["POST","true"]
        -
        -=== Forced lock over another deployer's lock, every overwrite attempt returns a 504 and is not applied: the error is the 504
        -
        ->>> [CLI] bundle deploy --force-lock
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -Warn: retrying after 504 Gateway Timeout from POST /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
         Error: Failed to acquire deployment lock: Fault injected by test.
         Error: Fault injected by test. (504 INJECTED)
         
        -Endpoint: POST [DATABRICKS_URL]/api/2.0/workspace-files/import-file/Workspace%2FUsers%2F[USERNAME]%2F.bundle%2Ftest-bundle%2Fdefault%2Fstate%2Fdeploy.lock?overwrite=true
        +Endpoint: POST [DATABRICKS_URL]/api/2.0/workspace-files/import-file/Workspace%2FUsers%2F[USERNAME]%2F.bundle%2Ftest-bundle%2Fdefault%2Fstate%2Fdeploy.lock?overwrite=false
         HTTP Status: 504 Gateway Timeout
         API error_code: INJECTED
         API message: Fault injected by test.
         
         
         Exit code: 1
        -["POST","true"]
        -["POST","true"]
        -["POST","true"]

latest (v1.26.0): same output as main (2699068)

TestAccept/bundle/deploy/lock-timeout/DMS=: branch ✅ | main (2699068) ❌ | latest (v1.26.0) ❌

main (2699068):

prepare_server.go:300: request canceled: context canceled
    acceptance_test.go:1374: Diff:
        --- bundle/deploy/lock-timeout/output.txt
        +++ /tmp/TestAcceptbundledeploylock-timeoutDMS=2195525541/002/output.txt
        @@ -1,8 +1,4 @@
        -Warn: retrying after Post "[DATABRICKS_URL]/api/2.0/workspace-files/import-file/Workspace%2FUsers%2F[USERNAME]%2F.bundle%2Ftest-bundle%2Fdefault%2Fstate%2Fdeploy.lock?overwrite=false": request timed out after 5s of inactivity
        -Warn: retrying after Post "[DATABRICKS_URL]/api/2.0/workspace-files/import-file/Workspace%2FUsers%2F[USERNAME]%2F.bundle%2Ftest-bundle%2Fdefault%2Fstate%2Fdeploy.lock?overwrite=false": request timed out after 5s of inactivity
         Error: Failed to acquire deployment lock: Post "[DATABRICKS_URL]/api/2.0/workspace-files/import-file/Workspace%2FUsers%2F[USERNAME]%2F.bundle%2Ftest-bundle%2Fdefault%2Fstate%2Fdeploy.lock?overwrite=false": request timed out after 5s of inactivity
         Error: Post "[DATABRICKS_URL]/api/2.0/workspace-files/import-file/Workspace%2FUsers%2F[USERNAME]%2F.bundle%2Ftest-bundle%2Fdefault%2Fstate%2Fdeploy.lock?overwrite=false": request timed out after 5s of inactivity
         
         /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -/api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -/api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock

latest (v1.26.0): same output as main (2699068)

TestAccept/bundle/deploy/lock-timeout/DMS=true: branch ✅ | main (2699068) ❌ | latest (v1.26.0) ❌

main (2699068):

prepare_server.go:300: request canceled: context canceled
    acceptance_test.go:1374: Diff:
        --- bundle/deploy/lock-timeout/output.txt
        +++ /tmp/TestAcceptbundledeploylock-timeoutDMS=true1651648888/002/output.txt
        @@ -1,8 +1,4 @@
        -Warn: retrying after Post "[DATABRICKS_URL]/api/2.0/workspace-files/import-file/Workspace%2FUsers%2F[USERNAME]%2F.bundle%2Ftest-bundle%2Fdefault%2Fstate%2Fdeploy.lock?overwrite=false": request timed out after 5s of inactivity
        -Warn: retrying after Post "[DATABRICKS_URL]/api/2.0/workspace-files/import-file/Workspace%2FUsers%2F[USERNAME]%2F.bundle%2Ftest-bundle%2Fdefault%2Fstate%2Fdeploy.lock?overwrite=false": request timed out after 5s of inactivity
         Error: Failed to acquire deployment lock: Post "[DATABRICKS_URL]/api/2.0/workspace-files/import-file/Workspace%2FUsers%2F[USERNAME]%2F.bundle%2Ftest-bundle%2Fdefault%2Fstate%2Fdeploy.lock?overwrite=false": request timed out after 5s of inactivity
         Error: Post "[DATABRICKS_URL]/api/2.0/workspace-files/import-file/Workspace%2FUsers%2F[USERNAME]%2F.bundle%2Ftest-bundle%2Fdefault%2Fstate%2Fdeploy.lock?overwrite=false": request timed out after 5s of inactivity
         
         /api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -/api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        -/api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/test-bundle/default/state/deploy.lock
        
FAIL

latest (v1.26.0): same output as main (2699068)

The last attempt may have been applied even though its response was lost;
without the read-back, that lock would stay behind with nobody to release
it. Also add a lock-timeout test for the inactivity timeout with retries
exhausted.

Co-authored-by: Isaac <no-reply@databricks.com>
@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Integration test report

Commit: f440de2

Run: 43722837151

Env ✅​pass 🙈​skip Time
✅​ aws linux-2core-8gb 271 18 3:40
✅​ aws-windows-latest-4core-16gb 273 16 3:33
✅​ azure linux-2core-8gb 270 18 3:30
✅​ azure-windows-latest-4core-16gb 272 16 2:51
✅​ gcp linux-2core-8gb 271 18 3:30
✅​ gcp-windows-latest-4core-16gb 273 16 2:41
Top 3 slowest tests (at least 2 minutes):
duration env testname
3:28 aws-windows-latest-4core-16gb TestAccept
2:46 azure-windows-latest-4core-16gb TestAccept
2:37 gcp-windows-latest-4core-16gb TestAccept

Co-authored-by: Isaac <no-reply@databricks.com>
@denik
denik marked this pull request as ready for review November 13, 2026 09:59
@denik
denik requested review from a team as code owners November 13, 2026 09:59

@Sankalp-Mittal Sankalp-Mittal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI review from review-factory: 3 independent reviewer models (Claude Opus 5.5, Claude Sonnet 5.5, Claude Fable 5.2) with cross-verification. Only findings that reviewers agreed on are posted.

Retries the non-forced deploy lock create on transient errors with a read-back; the main finding is a telemetry test that now sleeps about 30s.

Findings: 2 minor, 2 nit.

  • acceptance/bundle/telemetry/deploy-failed-engine-unknown/test.toml:14 minor: Existing 500-stub telemetry test now sleeps about 30s in lock-create retries

acceptance/bundle/telemetry/deploy-failed-engine-unknown stubs every POST /api/2.0/workspace-files/import-file/{path...} with a 500, and the first write to fail is the deploy.lock create. Before this PR that create was not retried. It now goes through retry.With(ctx, retry.IsTransient, ...) (libs/locker/locker.go:158-160), and a 500 the SDK does not retry counts as transient (libs/retry/retry_test.go:22). The test therefore makes 3 attempts with the default 15s pause between them (libs/retry/retry.go:21,26), about 30s of extra sleeping, because it does not set DATABRICKS_BUNDLE_RETRY_INTERVAL_MS.

Nothing turns red: the root SuppressLines.warn_retry hides the retry warnings, and the final error is the same 500, so the golden output still matches. The cost is runtime only, but it uses half of the 60s local timeout (acceptance/test.toml:8; 90s on Windows), so a loaded runner could get close to it. bundle/telemetry is also not in the list of suites the PR description says were run.

Suggested fix: add Env.DATABRICKS_BUNDLE_RETRY_INTERVAL_MS = "100" to this test.toml, as the other tests that inject 5xx on import-file do (for example acceptance/bundle/deploy/files/upload-504/test.toml and acceptance/bundle/upload/internal_server_error/test.toml). The 30s figure comes from reading the code; no reviewer could run the test.

Agreed by 3 reviewer model(s).

Comment thread libs/locker/locker.go Resolved
Comment thread libs/locker/locker.go Resolved
Comment thread libs/locker/locker.go Resolved
denik and others added 2 commits November 15, 2026 09:53
A connection cut mid-response leaves the same uncertainty as a timeout,
and the lock's unique ID plus the read-back make a retry safe either way.
fault.py cannot cut a connection, so this is covered by unit tests in
libs/locker.

Co-authored-by: Isaac <no-reply@databricks.com>
Address review: when the last create attempt fails transiently and the
read-back finds another holder's lock, report the holder rather than the
transient error. Add lock-retry cases for that and for --force-lock, and
shorten the retry pauses in the telemetry test that stubs import-file
with a 500.

Co-authored-by: Isaac <no-reply@databricks.com>
@denik

denik commented Nov 15, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the review in aafff5e:

  • telemetry test sleeping ~30s: confirmed locally (30.07s). deploy-failed-engine-unknown/test.toml now sets DATABRICKS_BUNDLE_RETRY_INTERVAL_MS = "100" (0.26s); golden output unchanged.
  • forced locks / holder message / worst-case time: see the replies on the inline threads.

AI agent (harness_auto)

@Sankalp-Mittal Sankalp-Mittal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI review (Claude Fable 5.2 + Claude Opus 5.5, cross-verified). Only points the reviewers agreed on are posted.

Comment thread libs/locker/locker.go Resolved
Address review: with --force-lock, an overwrite that failed transiently
and was not applied returned the holder error, which suggests
--force-lock. Return the write error instead.

Co-authored-by: Isaac <no-reply@databricks.com>

@Sankalp-Mittal Sankalp-Mittal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI review (Claude Fable 5.2 + Claude Opus 5.5, cross-verified). Only points the reviewers agreed on are posted.

Comment thread libs/locker/locker.go Resolved
Co-authored-by: Isaac <no-reply@databricks.com>

@Sankalp-Mittal Sankalp-Mittal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI review (Claude Fable 5.2 + Claude Opus 5.5, cross-verified). Only points the reviewers agreed on are posted.

Co-authored-by: Isaac <no-reply@databricks.com>

@Sankalp-Mittal Sankalp-Mittal left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI review (Claude Fable 5.2 + Claude Opus 5.5, cross-verified). Only points the reviewers agreed on are posted.

No issues found.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-auto PRs made by AI loops & factories, DABs DABs related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants