@@ -43,7 +43,8 @@ type Manager interface {
43
43
// RunWorkloadDetached runs a container in the background.
44
44
RunWorkloadDetached (runConfig * runner.RunConfig ) error
45
45
// RestartWorkload restarts a previously stopped container.
46
- RestartWorkload (ctx context.Context , name string ) error
46
+ // It is implemented as an asynchronous operation which returns an errgroup.Group
47
+ RestartWorkload (ctx context.Context , name string ) (* errgroup.Group , error )
47
48
}
48
49
49
50
type defaultManager struct {
@@ -159,17 +160,12 @@ func (d *defaultManager) StopWorkload(ctx context.Context, name string) (*errgro
159
160
return nil , err
160
161
}
161
162
162
- containerID := container .ID
163
- containerBaseName := labels .GetContainerBaseName (container .Labels )
164
163
running := isContainerRunning (container )
165
-
166
164
if ! running {
167
165
return nil , fmt .Errorf ("%w: %s" , ErrContainerNotRunning , name )
168
166
}
169
167
170
- workload := stopWorkloadRequest {Name : containerBaseName , ID : containerID }
171
- // Do the actual stop operation in the background, and return an error group.
172
- return d .stopWorkloads (ctx , []stopWorkloadRequest {workload }), nil
168
+ return d .stopWorkloads (ctx , []* rt.ContainerInfo {container }), nil
173
169
}
174
170
175
171
func (d * defaultManager ) StopAllWorkloads (ctx context.Context ) (* errgroup.Group , error ) {
@@ -181,16 +177,15 @@ func (d *defaultManager) StopAllWorkloads(ctx context.Context) (*errgroup.Group,
181
177
182
178
// Duplicates the logic of GetWorkloads, but is simple enough that it's not
183
179
// worth duplicating.
184
- stopRequests := make ([] stopWorkloadRequest , 0 , len ( containers ))
180
+ var containersToStop [] * rt. ContainerInfo
185
181
for _ , c := range containers {
186
182
// If the caller did not set `listAll` to true, only include running containers.
187
183
if labels .IsToolHiveContainer (c .Labels ) && isContainerRunning (& c ) {
188
- req := stopWorkloadRequest {Name : labels .GetContainerBaseName (c .Labels ), ID : c .ID }
189
- stopRequests = append (stopRequests , req )
184
+ containersToStop = append (containersToStop , & c )
190
185
}
191
186
}
192
187
193
- return d .stopWorkloads (ctx , stopRequests ), nil
188
+ return d .stopWorkloads (ctx , containersToStop ), nil
194
189
}
195
190
196
191
func (* defaultManager ) RunWorkload (ctx context.Context , runConfig * runner.RunConfig ) error {
@@ -395,7 +390,7 @@ func (*defaultManager) RunWorkloadDetached(runConfig *runner.RunConfig) error {
395
390
return nil
396
391
}
397
392
398
- func (d * defaultManager ) RestartWorkload (ctx context.Context , name string ) error {
393
+ func (d * defaultManager ) RestartWorkload (ctx context.Context , name string ) ( * errgroup. Group , error ) {
399
394
var containerBaseName string
400
395
var running bool
401
396
// Try to find the container.
@@ -418,30 +413,41 @@ func (d *defaultManager) RestartWorkload(ctx context.Context, name string) error
418
413
419
414
if running && proxyRunning {
420
415
logger .Infof ("Container %s and proxy are already running" , name )
421
- return nil
422
- }
423
-
424
- containerID := container .ID
425
- // If the container is running but the proxy is not, stop the container first
426
- if container .ID != "" && running { // && !proxyRunning was previously here but is implied by previous if statement.
427
- logger .Infof ("Container %s is running but proxy is not. Stopping container..." , name )
428
- if err := d .runtime .StopWorkload (ctx , containerID ); err != nil {
429
- return fmt .Errorf ("failed to stop container: %v" , err )
430
- }
431
- logger .Infof ("Container %s stopped" , name )
416
+ // Return empty error group so that client does not need to check for nil.
417
+ return & errgroup.Group {}, nil
432
418
}
433
419
434
420
// Load the configuration from the state store
421
+ // This is done synchronously since it is relatively inexpensive operation
422
+ // and it allows for better error handling.
435
423
mcpRunner , err := d .loadRunnerFromState (ctx , containerBaseName )
436
424
if err != nil {
437
- return fmt .Errorf ("failed to load state for %s: %v" , containerBaseName , err )
425
+ return nil , fmt .Errorf ("failed to load state for %s: %v" , containerBaseName , err )
438
426
}
439
-
440
427
logger .Infof ("Loaded configuration from state for %s" , containerBaseName )
441
428
442
429
// Run the tooling server inside a detached process.
430
+ // TODO: This will need to be changed when RunWorkloadDetached is converted
431
+ // to be async.
443
432
logger .Infof ("Starting tooling server %s..." , name )
444
- return d .RunWorkloadDetached (mcpRunner .Config )
433
+ runGroup := & errgroup.Group {}
434
+ runGroup .Go (func () error {
435
+ containerID := container .ID
436
+ // If the container is running but the proxy is not, stop the container first
437
+ if container .ID != "" && running { // && !proxyRunning was previously here but is implied by previous if statement.
438
+ logger .Infof ("Container %s is running but proxy is not. Stopping container..." , name )
439
+ // n.b. - we do not reuse the `StopWorkload` method here because it
440
+ // does some extra things which are not appropriate for resuming a workload.
441
+ if err = d .runtime .StopWorkload (ctx , containerID ); err != nil {
442
+ return fmt .Errorf ("failed to stop container %s: %v" , name , err )
443
+ }
444
+ logger .Infof ("Container %s stopped" , name )
445
+ }
446
+
447
+ return d .RunWorkloadDetached (mcpRunner .Config )
448
+ })
449
+
450
+ return runGroup , nil
445
451
}
446
452
447
453
func (d * defaultManager ) findContainerByName (ctx context.Context , name string ) (* rt.ContainerInfo , error ) {
@@ -555,36 +561,31 @@ func (*defaultManager) cleanupTempPermissionProfile(ctx context.Context, baseNam
555
561
return nil
556
562
}
557
563
558
- // Internal type used when stopping workloads.
559
- type stopWorkloadRequest struct {
560
- Name string
561
- ID string
562
- }
563
-
564
564
// stopWorkloads stops the named workloads concurrently.
565
565
// It assumes that the workloads exist in the running state.
566
- func (d * defaultManager ) stopWorkloads (ctx context.Context , workloads []stopWorkloadRequest ) * errgroup.Group {
566
+ func (d * defaultManager ) stopWorkloads (ctx context.Context , workloads []* rt. ContainerInfo ) * errgroup.Group {
567
567
group := errgroup.Group {}
568
568
for _ , workload := range workloads {
569
569
group .Go (func () error {
570
+ name := labels .GetContainerBaseName (workload .Labels )
570
571
// Stop the proxy process
571
- proxy .StopProcess (workload . Name )
572
+ proxy .StopProcess (name )
572
573
573
- logger .Infof ("Stopping containers for %s..." , workload . Name )
574
+ logger .Infof ("Stopping containers for %s..." , name )
574
575
// Stop the container
575
576
if err := d .runtime .StopWorkload (ctx , workload .ID ); err != nil {
576
577
return fmt .Errorf ("failed to stop container: %w" , err )
577
578
}
578
579
579
580
if shouldRemoveClientConfig () {
580
- if err := removeClientConfigurations (workload . Name ); err != nil {
581
+ if err := removeClientConfigurations (name ); err != nil {
581
582
logger .Warnf ("Warning: Failed to remove client configurations: %v" , err )
582
583
} else {
583
- logger .Infof ("Client configurations for %s removed" , workload . Name )
584
+ logger .Infof ("Client configurations for %s removed" , name )
584
585
}
585
586
}
586
587
587
- logger .Infof ("Successfully stopped %s..." , workload . Name )
588
+ logger .Infof ("Successfully stopped %s..." , name )
588
589
return nil
589
590
})
590
591
}
0 commit comments