Skip to content

Commit 8f0c24a

Browse files
committed
[ws-manager, supervisor, bridge] Prebuild workspaces are done when their container stops
1 parent 334c135 commit 8f0c24a

File tree

57 files changed

+2527
-1464
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+2527
-1464
lines changed

components/supervisor/pkg/supervisor/supervisor.go

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,13 @@ const (
9595
KindGit = "git"
9696
)
9797

98+
type ShutdownReason int16
99+
100+
const (
101+
ShutdownReasonSuccess ShutdownReason = 0
102+
ShutdownReasonExecutionError ShutdownReason = 1
103+
)
104+
98105
// Run serves as main entrypoint to the supervisor
99106
func Run(options ...RunOption) {
100107
defer log.Info("supervisor shut down")
@@ -148,7 +155,7 @@ func Run(options ...RunOption) {
148155

149156
ctx, cancel := context.WithCancel(context.Background())
150157
var (
151-
shutdown = make(chan struct{})
158+
shutdown = make(chan ShutdownReason, 1)
152159
ideReady = &ideReadyState{cond: sync.NewCond(&sync.Mutex{})}
153160
cstate = NewInMemoryContentState(cfg.RepoRoot)
154161
gitpodService = createGitpodService(cfg, tokenService)
@@ -202,7 +209,7 @@ func Run(options ...RunOption) {
202209
// When in terminating mode, the reaper will send SIGTERM to each child that gets reparented
203210
// to us and is still running. We use this mechanism to send SIGTERM to a shell child processes
204211
// that get reparented once their parent shell terminates during shutdown.
205-
terminatingReaper := make(chan bool)
212+
terminatingReaper := make(chan bool, 1)
206213
// We keep the reaper until the bitter end because:
207214
// - it doesn't need graceful shutdown
208215
// - we want to do as much work as possible (SIGTERM'ing reparented processes during shutdown).
@@ -220,11 +227,15 @@ func Run(options ...RunOption) {
220227
wg.Add(1)
221228
go startSSHServer(ctx, cfg, &wg)
222229
wg.Add(1)
223-
go taskManager.Run(ctx, &wg)
230+
tasksSuccessChan := make(chan bool, 1)
231+
go taskManager.Run(ctx, &wg, tasksSuccessChan)
224232
wg.Add(1)
225233
go socketActivationForDocker(ctx, &wg, termMux)
226234

227-
if !cfg.isHeadless() {
235+
if cfg.isHeadless() {
236+
wg.Add(1)
237+
go stopWhenTasksAreDone(ctx, &wg, shutdown, tasksSuccessChan)
238+
} else {
228239
wg.Add(1)
229240
go portMgmt.Run(ctx, &wg)
230241
}
@@ -236,18 +247,20 @@ func Run(options ...RunOption) {
236247
}
237248

238249
log.Error("metadata access is possible - shutting down")
239-
close(shutdown)
250+
shutdown <- ShutdownReasonExecutionError
240251
}()
241252
}
242253

243254
sigChan := make(chan os.Signal, 1)
244255
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
256+
var exitCode int
245257
select {
246258
case <-sigChan:
247-
case <-shutdown:
259+
case shutdownReason := <-shutdown:
260+
exitCode = int(shutdownReason)
248261
}
249262

250-
log.Info("received SIGTERM - tearing down")
263+
log.Info("received SIGTERM (or shutdown) - tearing down")
251264
terminatingReaper <- true
252265
cancel()
253266
err = termMux.Close()
@@ -260,6 +273,9 @@ func Run(options ...RunOption) {
260273
terminateChildProcesses()
261274

262275
wg.Wait()
276+
277+
log.WithField("exitCode", exitCode).Debug("supervisor exit")
278+
os.Exit(exitCode)
263279
}
264280

265281
func createGitpodService(cfg *Config, tknsrv api.TokenServiceServer) *gitpod.APIoverJSONRPC {
@@ -772,6 +788,22 @@ func tunnelOverSSH(ctx context.Context, tunneled *ports.TunneledPortsService, ne
772788
<-ctx.Done()
773789
}
774790

791+
func stopWhenTasksAreDone(ctx context.Context, wg *sync.WaitGroup, shutdown chan ShutdownReason, successChan <-chan bool) {
792+
defer wg.Done()
793+
defer close(shutdown)
794+
795+
success := <-successChan
796+
if !success {
797+
// we signal task failure via kubernetes termination log
798+
msg := []byte("headless task failed")
799+
err := ioutil.WriteFile("/dev/termination-log", msg, 0644)
800+
if err != nil {
801+
log.WithError(err).Error("err while writing termination log")
802+
}
803+
}
804+
shutdown <- ShutdownReasonSuccess
805+
}
806+
775807
func startSSHServer(ctx context.Context, cfg *Config, wg *sync.WaitGroup) {
776808
defer wg.Done()
777809

components/supervisor/pkg/supervisor/tasks.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ func (tm *tasksManager) init(ctx context.Context) {
205205
}
206206
}
207207

208-
func (tm *tasksManager) Run(ctx context.Context, wg *sync.WaitGroup) {
208+
func (tm *tasksManager) Run(ctx context.Context, wg *sync.WaitGroup, successChan chan bool) {
209209
defer wg.Done()
210210
defer log.Debug("tasksManager shutdown")
211211

@@ -275,7 +275,8 @@ func (tm *tasksManager) Run(ctx context.Context, wg *sync.WaitGroup) {
275275
for _, task := range tm.tasks {
276276
select {
277277
case <-ctx.Done():
278-
return
278+
success = false
279+
break
279280
case taskSuccess := <-task.successChan:
280281
if !taskSuccess {
281282
success = false
@@ -286,6 +287,7 @@ func (tm *tasksManager) Run(ctx context.Context, wg *sync.WaitGroup) {
286287
if tm.config.isHeadless() {
287288
tm.reporter.done(success)
288289
}
290+
successChan <- success
289291
}
290292

291293
func (tm *tasksManager) getCommand(task *task) string {

components/supervisor/pkg/supervisor/tasks_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ func TestTaskManager(t *testing.T) {
131131
contentState.MarkContentReady(test.Source)
132132
var wg sync.WaitGroup
133133
wg.Add(1)
134-
go taskManager.Run(context.Background(), &wg)
134+
tasksSuccessChan := make(chan bool, 1)
135+
go taskManager.Run(context.Background(), &wg, tasksSuccessChan)
135136
wg.Wait()
136137
if diff := cmp.Diff(test.ExpectedReporter, reporter); diff != "" {
137138
t.Errorf("unexpected output (-want +got):\n%s", diff)

0 commit comments

Comments
 (0)