Detach prepared execution ownership from runners
This commit is contained in:
@@ -22,7 +22,7 @@ const (
|
||||
|
||||
// PreparedExecution owns one frozen, single-use runner execution.
|
||||
type PreparedExecution struct {
|
||||
owner *Runner
|
||||
owner *runnerIdentity
|
||||
mu sync.Mutex
|
||||
state preparedExecutionState
|
||||
details *domain.PreparedRun
|
||||
@@ -63,7 +63,7 @@ func (r *Runner) PrepareExecution(ctx context.Context, req domain.RunRequest) (*
|
||||
}
|
||||
|
||||
return &PreparedExecution{
|
||||
owner: r,
|
||||
owner: r.identity,
|
||||
state: preparedExecutionReady,
|
||||
details: details,
|
||||
payload: &preparedExecutionPayload{
|
||||
@@ -170,7 +170,7 @@ func (r *Runner) RunPrepared(ctx context.Context, prepared *PreparedExecution) (
|
||||
}
|
||||
|
||||
func (p *PreparedExecution) claim(owner *Runner) (*preparedExecutionPayload, error) {
|
||||
if p == nil || owner == nil || p.owner != owner {
|
||||
if p == nil || owner == nil || owner.identity == nil || p.owner != owner.identity {
|
||||
return nil, fmt.Errorf("%w: prepared execution does not belong to this runner", ErrInvalidRequest)
|
||||
}
|
||||
|
||||
|
||||
@@ -600,6 +600,9 @@ func TestRunnerPreparedExecutionOwnershipUseAndDiscard(t *testing.T) {
|
||||
}
|
||||
|
||||
owner := newRunner()
|
||||
if other := newRunner(); owner.identity == nil || owner.identity == other.identity {
|
||||
t.Fatal("constructed runners must have independent identity tokens")
|
||||
}
|
||||
prepared, err := owner.PrepareExecution(context.Background(), request)
|
||||
if err != nil {
|
||||
t.Fatalf("prepare execution: %v", err)
|
||||
@@ -616,6 +619,9 @@ func TestRunnerPreparedExecutionOwnershipUseAndDiscard(t *testing.T) {
|
||||
if prepared.Details() == nil {
|
||||
t.Fatal("details unavailable after execution")
|
||||
}
|
||||
if prepared.owner != owner.identity || prepared.payload != nil {
|
||||
t.Fatal("claimed handle retained payload or lost owner identity")
|
||||
}
|
||||
|
||||
discarded, err := owner.PrepareExecution(context.Background(), request)
|
||||
if err != nil {
|
||||
@@ -623,6 +629,9 @@ func TestRunnerPreparedExecutionOwnershipUseAndDiscard(t *testing.T) {
|
||||
}
|
||||
discarded.Discard()
|
||||
discarded.Discard()
|
||||
if discarded.owner != owner.identity || discarded.payload != nil {
|
||||
t.Fatal("discarded handle retained payload or lost owner identity")
|
||||
}
|
||||
if _, err := owner.RunPrepared(context.Background(), discarded); !errors.Is(err, ErrInvalidRequest) {
|
||||
t.Fatalf("discarded execution error=%v, want ErrInvalidRequest", err)
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ var (
|
||||
|
||||
// Runner executes the Promptkit core use case.
|
||||
type Runner struct {
|
||||
identity *runnerIdentity
|
||||
promptDefs promptdef.Repository
|
||||
profiles profile.Repository
|
||||
artifacts artifact.Reader
|
||||
@@ -54,6 +55,10 @@ type Runner struct {
|
||||
defaultTransientRetries uint64
|
||||
}
|
||||
|
||||
// A non-zero-sized token gives each constructed runner a distinct identity
|
||||
// without retaining its collaborators in prepared handles.
|
||||
type runnerIdentity struct{ marker byte }
|
||||
|
||||
// RunAdmitter reserves capacity for one resolved backend run.
|
||||
type RunAdmitter interface {
|
||||
Admit(context.Context, string) (func(), error)
|
||||
@@ -113,6 +118,7 @@ func NewRunnerWithRepairer(
|
||||
retries = defaultTransientRetries[0]
|
||||
}
|
||||
return &Runner{
|
||||
identity: &runnerIdentity{},
|
||||
promptDefs: promptDefs,
|
||||
profiles: profiles,
|
||||
artifacts: artifacts,
|
||||
|
||||
Reference in New Issue
Block a user