Skip to content

Commit 786f578

Browse files
committed
direct: simplify Engine API: SaveState(id, state) replaces SetID+SaveState
Collapse the two-step engine.SetID(id) / engine.SaveState(state) pattern into a single engine.SaveState(id, state) call. The Engine still tracks the id internally and panics if a subsequent call passes a different id (guards against bugs). Also extract the polling loop from vector_search_index.DoCreate into a private waitForIndexReady helper so that the unchanged DoDelete stays between the two functions and does not appear in the diff. Co-authored-by: Denis Bilenko
1 parent d563c76 commit 786f578

9 files changed

Lines changed: 40 additions & 42 deletions

File tree

bundle/direct/apply.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,6 @@ func (d *DeploymentUnit) Update(ctx context.Context, db *dstate.DeploymentState,
129129
engine := dresources.NewEngine(d.Adapter.StateType(), func(_ string, x any) error {
130130
return db.SaveState(d.ResourceKey, id, x, d.DependsOn)
131131
})
132-
engine.SetID(id)
133-
134132
remoteState, err := retryOnTransient(ctx, func() (any, error) {
135133
return d.Adapter.DoUpdate(ctx, engine, id, newState, planEntry)
136134
})

bundle/direct/dresources/adapter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ type IResource interface {
5353

5454
// DoCreate creates a new resource from the newState. Returns id of the resource and optionally remote state.
5555
// If remote state is available as part of the operation, return it; otherwise return nil.
56-
// Call engine.SetID then engine.SaveState to persist intermediate state before long-running waits.
56+
// Call engine.SaveState(id, state) to persist intermediate state before long-running waits.
5757
// Example: func (r *ResourceVolume) DoCreate(ctx context.Context, _ *Engine, newState *catalog.CreateVolumeRequestContent) (string, *catalog.VolumeInfo, error)
5858
DoCreate(ctx context.Context, engine *Engine, newState any) (id string, remoteState any, e error)
5959

bundle/direct/dresources/app.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ func (r *ResourceApp) DoCreate(ctx context.Context, engine *Engine, config *AppS
156156

157157
// Save state as soon as the app exists so it is not orphaned if the wait or
158158
// lifecycle management is interrupted.
159-
engine.SetID(app.Name)
160-
if err := engine.SaveState(config); err != nil {
159+
160+
if err := engine.SaveState(app.Name, config); err != nil {
161161
return "", nil, err
162162
}
163163

bundle/direct/dresources/cluster.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,7 @@ func (r *ResourceCluster) DoCreate(ctx context.Context, engine *Engine, config *
156156

157157
// Save state immediately after the cluster is created so it is not orphaned
158158
// if the subsequent wait or terminate is interrupted.
159-
engine.SetID(id)
160-
if err := engine.SaveState(config); err != nil {
159+
if err := engine.SaveState(id, config); err != nil {
161160
return "", nil, err
162161
}
163162

bundle/direct/dresources/database_instance.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ func (d *ResourceDatabaseInstance) DoCreate(ctx context.Context, engine *Engine,
3636

3737
// Save state immediately after the instance is created so it is not orphaned
3838
// if the subsequent wait is interrupted.
39-
engine.SetID(id)
40-
if err := engine.SaveState(config); err != nil {
39+
if err := engine.SaveState(id, config); err != nil {
4140
return "", nil, err
4241
}
4342

bundle/direct/dresources/engine.go

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package dresources
22

33
import (
4-
"errors"
54
"fmt"
65
"reflect"
76
)
@@ -26,18 +25,14 @@ func NewNopEngine(stateType reflect.Type) *Engine {
2625
return NewEngine(stateType, func(_ string, _ any) error { return nil })
2726
}
2827

29-
// SetID sets the resource id for subsequent SaveState calls.
30-
// Must be called before SaveState during DoCreate; for DoUpdate the Engine is
31-
// pre-configured with the existing id.
32-
func (e *Engine) SetID(id string) {
33-
e.id = id
34-
}
35-
36-
// SaveState saves the resource state. x must be of the same pointer-to-struct
37-
// type as the resource's state type. Returns an error if SetID was not called.
38-
func (e *Engine) SaveState(x any) error {
28+
// SaveState saves the resource state. id must be the resource's identifier; on
29+
// the first call it is recorded, and subsequent calls panic if a different id is
30+
// passed. x must be a pointer to the same struct type as the resource's state.
31+
func (e *Engine) SaveState(id string, x any) error {
3932
if e.id == "" {
40-
return errors.New("SaveState: id not set, call SetID first")
33+
e.id = id
34+
} else if e.id != id {
35+
panic(fmt.Sprintf("SaveState: id mismatch: expected %q, got %q", e.id, id))
4136
}
4237
xt := reflect.TypeOf(x)
4338
if xt != e.stateType {

bundle/direct/dresources/model_serving_endpoint.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,7 @@ func (r *ResourceModelServingEndpoint) DoCreate(ctx context.Context, engine *Eng
137137

138138
// Save state immediately after the endpoint is created so it is not orphaned
139139
// if the subsequent wait is interrupted.
140-
engine.SetID(id)
141-
if err := engine.SaveState(config); err != nil {
140+
if err := engine.SaveState(id, config); err != nil {
142141
return "", nil, err
143142
}
144143

bundle/direct/dresources/vector_search_endpoint.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,7 @@ func (r *ResourceVectorSearchEndpoint) DoCreate(ctx context.Context, engine *Eng
7474

7575
// Save state immediately after the endpoint is created so it is not orphaned
7676
// if the subsequent wait is interrupted.
77-
engine.SetID(id)
78-
if err := engine.SaveState(config); err != nil {
77+
if err := engine.SaveState(id, config); err != nil {
7978
return "", nil, err
8079
}
8180

bundle/direct/dresources/vector_search_index.go

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,34 @@ func (r *ResourceVectorSearchIndex) DoCreate(ctx context.Context, engine *Engine
138138

139139
// Save state immediately after the index is created (endpoint UUID now set) so it
140140
// is not orphaned if the subsequent provisioning wait is interrupted.
141-
engine.SetID(config.Name)
142-
if err := engine.SaveState(config); err != nil {
141+
if err := engine.SaveState(config.Name, config); err != nil {
143142
return "", nil, err
144143
}
145144

146-
// CreateIndex returns immediately; poll until the embedding pipeline is ready so
147-
// dependent resources and the next plan see a usable index.
145+
remote, err := r.waitForIndexReady(ctx, config.Name, endpointUuid)
146+
if err != nil {
147+
return "", nil, err
148+
}
149+
return config.Name, remote, nil
150+
}
151+
152+
// No DoUpdate: vector search indexes have no update API. All SDK fields are
153+
// declared in resources.yml under recreate_on_changes or ignore_remote_changes.
154+
// If a future SDK bump adds a new field that isn't classified, the framework
155+
// rejects the resulting Update plan at bundle_plan.go (see also the reflection
156+
// test in vector_search_index_test.go which catches it earlier at unit-test time).
157+
158+
func (r *ResourceVectorSearchIndex) DoDelete(ctx context.Context, id string, _ *VectorSearchIndexState) error {
159+
return r.client.VectorSearchIndexes.DeleteIndexByIndexName(ctx, id)
160+
}
161+
162+
// waitForIndexReady polls GetIndex until Status.Ready=true. CreateIndex returns
163+
// immediately with metadata of an index whose embedding pipeline is still
164+
// provisioning; queries against an index that isn't ready fail. Blocking here
165+
// lets dependent resources (and the next plan) see a usable index.
166+
func (r *ResourceVectorSearchIndex) waitForIndexReady(ctx context.Context, id, endpointUuid string) (*VectorSearchIndexRemote, error) {
148167
index, err := retries.Poll(ctx, createIndexTimeout, func() (*vectorsearch.VectorIndex, *retries.Err) {
149-
idx, getErr := r.client.VectorSearchIndexes.GetIndexByIndexName(ctx, config.Name)
168+
idx, getErr := r.client.VectorSearchIndexes.GetIndexByIndexName(ctx, id)
150169
if getErr != nil {
151170
return nil, retries.Halt(getErr)
152171
}
@@ -160,19 +179,9 @@ func (r *ResourceVectorSearchIndex) DoCreate(ctx context.Context, engine *Engine
160179
return idx, nil
161180
})
162181
if err != nil {
163-
return "", nil, err
182+
return nil, err
164183
}
165-
return config.Name, &VectorSearchIndexRemote{VectorIndex: *index, EndpointUuid: endpointUuid}, nil
166-
}
167-
168-
// No DoUpdate: vector search indexes have no update API. All SDK fields are
169-
// declared in resources.yml under recreate_on_changes or ignore_remote_changes.
170-
// If a future SDK bump adds a new field that isn't classified, the framework
171-
// rejects the resulting Update plan at bundle_plan.go (see also the reflection
172-
// test in vector_search_index_test.go which catches it earlier at unit-test time).
173-
174-
func (r *ResourceVectorSearchIndex) DoDelete(ctx context.Context, id string, _ *VectorSearchIndexState) error {
175-
return r.client.VectorSearchIndexes.DeleteIndexByIndexName(ctx, id)
184+
return &VectorSearchIndexRemote{VectorIndex: *index, EndpointUuid: endpointUuid}, nil
176185
}
177186

178187
// WaitAfterDelete polls GetIndex until it returns 404. The DELETE call is

0 commit comments

Comments
 (0)