Skip to content

feat: restart dependent services on project-level service restart#3103

Open
pkoutsovasilis wants to merge 6 commits into
getarcaneapp:mainfrom
pkoutsovasilis:feat/dependent_services_restart
Open

feat: restart dependent services on project-level service restart#3103
pkoutsovasilis wants to merge 6 commits into
getarcaneapp:mainfrom
pkoutsovasilis:feat/dependent_services_restart

Conversation

@pkoutsovasilis

@pkoutsovasilis pkoutsovasilis commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Checklist

  • This PR is not opened from my fork’s main branch
  • All new user-facing strings are translated via Paraglide (m.*())

What This PR Implements

What This PR Implements

Makes a per-service restart within a Compose project mirror docker compose restart <service>: it restarts the targeted service and every service that declares depends_on: { <svc>: { restart: true } } on it, in dependency order - instead of doing a raw single-container restart that left dependents running against a service that just restarted underneath them.

The per-service restart on the project detail page now routes through the project restart endpoint (the Compose engine) rather than a direct container restart. Restarting a container from the Containers screen is unchanged and still performs a plain container restart.

Addresses: #2935

Changes Made

Backend

  • pkg/projects/cmds.go - ComposeRestart now passes the loaded Project into api.RestartOptions, so the Compose engine resolves the dependency graph from the authoritative compose file and applies its IncludeDependents resolution (restart + restart:true dependents), matching the CLI.
  • internal/services/project_service.go - RestartProject(projectID, services, user) is now a single function: an empty services list restarts the whole project; a non-empty list restarts the named services (and their restart:true dependents).
  • api/handlers/projects.go - POST /environments/{id}/projects/{projectId}/restart accepts an optional repeatable services query parameter (?services=web&services=db) routed to RestartProject (no new endpoint; backward compatible - no services = restart whole project).

Frontend

  • lib/services/project-service.ts - restartProject(projectId, services?) sends the optional services as repeated services query params (URLSearchParams) and returns the response so the activity toast can link the resulting activity.
  • routes/(app)/projects/components/ProjectContainersTable.svelte - the per-row service restart now calls projectService.restartProject(projectId, [serviceName]) (with the standard spinner/toast/refresh handling) instead of a container restart. The action is gated on projects:restart to match the backend route's PermProjectsRestart, and reuses the shared ContainerActionMenuItem.

Testing Done

  • Backend: go build ./..., go vet, and go test for internal/services, api/handlers, pkg/projects, and pkg/libarcane/edge - all pass.
  • Frontend: pnpm check (touched files clean) and pnpm build succeed; Prettier formatting applied.
  • Full multi-stage container image build completes successfully end-to-end.
  • Manual testing: with a docker-compose project containing service dependencies (a service declaring depends_on: { <svc>: { restart: true } }), restarting the depended-on service from the project page restarted the dependent service(s) as well - matching docker compose restart <service>.

AI Tool Used (if applicable)

Claude Code (Anthropic, Opus 4.8)

Additional Context

  • The project services table currently has row selection disabled, so bulk multi-service restart is not reachable from that page; the single-service (per-row) restart is the affected path.

Disclaimer Greptiles Reviews use AI, make sure to check over its work.

To better help train Greptile on our codebase, if the comment is useful and valid Like the comment, if its not helpful or invalid Dislike

To have Greptile Re-Review the changes, mention greptileai.

Greptile Summary

This PR makes project-page service restarts use the Compose project restart flow. The main changes are:

  • Passes the loaded compose project into restart options so dependency restart rules are available.
  • Adds RestartProjectServices for targeted service restarts, with empty service lists restarting the whole project.
  • Allows the project restart endpoint to accept an optional services body.
  • Updates the project services table to restart a single service through the project API.

Confidence Score: 4/5

The change is mostly contained, with one authorization mismatch on the changed service restart UI path.

The backend restart flow appears coherent, but the frontend action uses the project restart API while retaining the container permission gate.

frontend/src/routes/(app)/projects/components/ProjectContainersTable.svelte

T-Rex T-Rex Logs

What T-Rex did

  • The focused permission-mismatch harness was run against the project services table, project service client, and backend restart route to validate the restart UI gating.
  • The harness showed that the row restart UI is gated by containers:restart and would be visible for a containers:restart-only role but hidden for a projects:restart-only role.
  • The harness did not reproduce the accepted mismatch because the exercised row restart block calls the container restart action, not projectService.restartProject.
  • Evidence shows the Go handler runtime endpoint evidence is blocked due to a timeout, so full endpoint details could not be produced.
  • The before/after compose-dependent restart tests show Before: RestartOptions.Project present: False with exit 1, and After: RestartOptions.Project present: True with services db, api and exit 0.
  • The UI restart execution flow was captured, including dependency install, Vite/Playwright commands, a middleware error, and a failed locator for the real Open menu button.

View all artifacts

T-Rex Ran code and verified through T-Rex

Fix All in Codex Fix All in Claude Code

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
frontend/src/routes/(app)/projects/components/ProjectContainersTable.svelte:508-509
**Use project restart permission**
This row action now calls `projectService.restartProject`, whose backend route is registered with `authz.PermProjectsRestart`. With the current `canRestartContainer` gate, users who only have `containers:restart` can see an action that fails authorization, while users who can restart projects but not containers cannot see the action.

Reviews (1): Last reviewed commit: "feat: restart dependent services on proj..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

Comment thread frontend/src/routes/(app)/projects/components/ProjectContainersTable.svelte Outdated
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown

This pull request has merge conflicts. Please resolve the conflicts so the PR can stay up-to-date and reviewed.

…es_restart

# Conflicts:
#	frontend/src/routes/(app)/projects/components/ProjectContainersTable.svelte
Comment thread backend/api/handlers/projects.go Outdated
EnvironmentID string `path:"id" doc:"Environment ID"`
ProjectID string `path:"projectId" doc:"Project ID"`
Body *struct {
Services []string `json:"services,omitempty" doc:"Service names to restart; empty restarts all services"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think instead of a Body we should just use a direct paramters of `

Services      []string `json:"services,omitempty" doc:"Service names to restart; empty restarts all services"`

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

changed in 829f419

}

func (s *ProjectService) RestartProject(ctx context.Context, projectID string, user models.User) error {
return s.RestartProjectServices(ctx, projectID, nil, user)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would just make one function for restarts, and in corperate logic if services isnt nil then restart only those

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

changed in 829f419

@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown

This pull request has merge conflicts. Please resolve the conflicts so the PR can stay up-to-date and reviewed.

…es_restart

# Conflicts:
#	backend/internal/services/project_service.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants