Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@cbergoon
Copy link

A common workflow in many projects is to run a set of services, make changes, build and restart the services. In process compose TUI the only path to accomplish this is to individually restart each process which is tedious.

This PR implements a "Restart All" shortcut that stops all of the processes and reruns them the same way it does when starting for the first time.

The shortcut is "Ctrl+U" and is made available in the footer as well as the "Shortcuts" menu.

Below is a summary of the changes included:

  • Implemented RestartAllProcesses method in the API and ProjectRunner.
  • Added route for restarting all processes.
  • Created client method to call the restart all processes API.
  • Integrated restart all processes action in TUI with confirmation dialog.
  • Updated shortcuts and help text for new action.
Screencast_20260123_161747.webm

- Implemented RestartAllProcesses method in the API and ProjectRunner.
- Added corresponding route for restarting all processes.
- Created client method to call the restart all processes API.
- Integrated restart all processes action in TUI with confirmation dialog.
- Updated shortcuts and help text for the new action.
Copilot AI review requested due to automatic review settings January 23, 2026 21:26
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a “Restart All Processes” capability across the backend API, client, and TUI so users can restart the whole process set in one operation instead of restarting each process individually.

Changes:

  • Extended the core runner (ProjectRunner) and IProject interface with a RestartAllProcesses operation that stops all running processes in a controlled order, resets internal state, and restarts them using the initial run order.
  • Exposed the restart-all behavior over HTTP via a new /processes/restart API route, added a corresponding client method, and wired it into the TUI’s shortcuts/help footer with a confirmation dialog and Ctrl+U binding.
  • Updated TUI shortcut configuration and help text to include the new “Restart All” action alongside existing process controls.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/tui/view.go Wires the new ActionProcessRestartAll shortcut to handleRestartAll and adds “Restart All” to the help footer so the action is discoverable in the TUI.
src/tui/proc-table.go Implements the confirmation modal and execution path (handleRestartAll / executeRestartAll) that invoke RestartAllProcesses with a progress indicator and error reporting.
src/tui/actions.go Defines the ActionProcessRestartAll action name, default Ctrl+U shortcut, ordering, and description for display in the help/footer UI.
src/client/restart.go Adds a low-level restartAllProcesses HTTP helper posting to /processes/restart, mirroring the existing single-process restart client.
src/client/client.go Exposes RestartAllProcesses as part of the public PcClient API used by the TUI and other callers.
src/app/project_runner.go Extends ProjectRunner with restart-all state (isRestartingAll), adjusts the main run loop to stay alive during restart-all, and implements RestartAllProcesses to orchestrate ordered shutdown, state reset, and restart.
src/app/project_interface.go Extends the IProject interface with a RestartAllProcesses method so both local and remote project implementations can support the new behavior.
src/api/routes.go Registers a new POST /processes/restart route, delegating to the API handler for restart-all.
src/api/pc_api.go Adds the RestartAllProcesses HTTP handler with Swagger annotations, invoking the project’s restart-all logic and returning a simple status payload.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +574 to +672
func (p *ProjectRunner) RestartAllProcesses() error {
log.Info().Msg("Restarting all processes")

// Set flag to prevent main loop from exiting when process count reaches 0
p.restartAllMutex.Lock()
p.isRestartingAll = true
p.restartAllMutex.Unlock()

// Build shutdown order
p.runProcMutex.Lock()
shutdownOrder := []*Process{}
if p.isOrderedShutdown {
err := p.project.WithProcesses([]string{}, func(process types.ProcessConfig) error {
if runningProc, ok := p.runningProcesses[process.ReplicaName]; ok {
shutdownOrder = append(shutdownOrder, runningProc)
}
return nil
})
if err != nil {
log.Error().Msgf("Failed to build project run order: %s", err.Error())
}
slices.Reverse(shutdownOrder)
} else {
for _, proc := range p.runningProcesses {
shutdownOrder = append(shutdownOrder, proc)
}
}
p.runProcMutex.Unlock()

var nameOrder []string
for _, v := range shutdownOrder {
nameOrder = append(nameOrder, v.getName())
}
log.Debug().Msgf("Stopping %d processes for restart. Order: %q", len(shutdownOrder), nameOrder)

// Prepare all processes for shutdown (prevents auto-restart)
for _, proc := range shutdownOrder {
proc.prepareForShutDown()
}

// Stop all processes
p.shutDownAndWait(shutdownOrder)

// Clear done processes map
p.doneProcMutex.Lock()
p.doneProcesses = make(map[string]*Process)
p.doneProcMutex.Unlock()

// Reset process states to pending
p.statesMutex.Lock()
for name, state := range p.processStates {
state.Status = types.ProcessStatePending
state.Pid = 0
state.ExitCode = 0
state.IsRunning = false
p.processStates[name] = state
}
p.statesMutex.Unlock()

// Build run order (same as initial Run())
runOrder := []types.ProcessConfig{}
err := p.project.WithProcesses([]string{}, func(process types.ProcessConfig) error {
if process.IsDeferred() {
return nil
}
runOrder = append(runOrder, process)
return nil
})
if err != nil {
// Clear the restart flag on error
p.restartAllMutex.Lock()
p.isRestartingAll = false
p.restartAllMutex.Unlock()
return fmt.Errorf("failed to build project run order: %w", err)
}

var startOrder []string
for _, v := range runOrder {
startOrder = append(startOrder, v.ReplicaName)
}
log.Debug().Msgf("Starting %d processes. Order: %q", len(runOrder), startOrder)

// Start all processes
for _, proc := range runOrder {
if proc.Schedule != nil && proc.Schedule.IsScheduled() {
continue
}
newConf := proc
p.runProcess(&newConf)
}

// Clear the restart flag now that new processes are started
p.restartAllMutex.Lock()
p.isRestartingAll = false
p.restartAllMutex.Unlock()

log.Info().Msg("All processes restarted")
return nil
}
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RestartAllProcesses introduces non-trivial shutdown and restart sequencing logic (including ordered shutdown, restart flags, and state resets), but there are currently no tests covering this method or the /processes/restart flow, while similar behavior (e.g., RestartProcess and other runner operations) is covered in project_runner_test.go and system_test.go. It would be valuable to add unit / system tests that exercise the restart-all path (including ordered vs. unordered shutdown and interaction with scheduled processes) to prevent regressions in this central control-flow.

Copilot uses AI. Check for mistakes.
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
12.6% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant