88 "github.com/databricks/cli/bundle/deployplan"
99 "github.com/databricks/cli/libs/log"
1010 "github.com/databricks/databricks-sdk-go"
11+ "github.com/databricks/databricks-sdk-go/apierr"
1112 "github.com/databricks/databricks-sdk-go/retries"
1213 "github.com/databricks/databricks-sdk-go/service/apps"
1314)
@@ -29,6 +30,12 @@ func (r *ResourceApp) DoRead(ctx context.Context, id string) (*apps.App, error)
2930}
3031
3132func (r * ResourceApp ) DoCreate (ctx context.Context , config * apps.App ) (string , * apps.App , error ) {
33+ // Wait for any existing app with the same name to be deleted.
34+ err := r .waitForDeletion (ctx , config .Name )
35+ if err != nil {
36+ return "" , nil , err
37+ }
38+
3239 request := apps.CreateAppRequest {
3340 App : * config ,
3441 NoCompute : true ,
@@ -74,6 +81,30 @@ func (r *ResourceApp) WaitAfterCreate(ctx context.Context, config *apps.App) (*a
7481 return r .waitForApp (ctx , r .client , config .Name )
7582}
7683
84+ // waitForDeletion waits for an app to be deleted if it exists and is in DELETING state.
85+ func (r * ResourceApp ) waitForDeletion (ctx context.Context , name string ) error {
86+ retrier := retries .New [struct {}](retries .WithTimeout (- 1 ), retries .WithRetryFunc (shouldRetry ))
87+ _ , err := retrier .Run (ctx , func (ctx context.Context ) (* struct {}, error ) {
88+ app , err := r .client .Apps .GetByName (ctx , name )
89+ if err != nil {
90+ if apierr .IsMissing (err ) {
91+ return nil , nil
92+ }
93+ return nil , retries .Halt (err )
94+ }
95+
96+ if app .ComputeStatus .State == apps .ComputeStateDeleting {
97+ log .Infof (ctx , "App %s is in DELETING state, waiting for it to be deleted..." , name )
98+ return nil , retries .Continues ("app is deleting" )
99+ }
100+
101+ // App exists but is not in DELETING state. This shouldn't happen in normal
102+ // flow since we only call DoCreate for new resources. Let Create API handle it.
103+ return nil , nil
104+ })
105+ return err
106+ }
107+
77108// waitForApp waits for the app to reach the target state. The target state is either ACTIVE or STOPPED.
78109// Apps with no_compute set to true will reach the STOPPED state, otherwise they will reach the ACTIVE state.
79110// We can't use the default waiter from SDK because it only waits on ACTIVE state but we need also STOPPED state.
0 commit comments