Skip to content

feat: full background activity tasks#2434

Draft
kmendell wants to merge 1 commit intomainfrom
feat/activity-tasks
Draft

feat: full background activity tasks#2434
kmendell wants to merge 1 commit intomainfrom
feat/activity-tasks

Conversation

@kmendell
Copy link
Copy Markdown
Member

@kmendell kmendell commented Apr 24, 2026

Checklist

  • This PR is not opened from my fork’s main branch

What This PR Implements

Fixes: #2415

Changes Made

Testing Done

  • Development environment started: ./scripts/development/dev.sh start
  • Frontend verified at http://localhost:3000
  • Backend verified at http://localhost:3552
  • Manual testing completed (describe):
  • No linting errors (e.g., just lint all)
  • Backend tests pass: just test backend

AI Tool Used (if applicable)

AI Tool:
Assistance Level:
What AI helped with:
I reviewed and edited all AI-generated output:
I ran all required tests and manually verified changes:

Additional Context

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 introduces a full "background activity" system for Arcane — a new activities + activity_messages table pair, an ActivityService with SSE fan-out for real-time updates, and a frontend activity-center UI. Activity tracking is wired into image-update checks, system prune, vulnerability scans, auto-update, project operations, and container bulk actions, with history pruned by the existing event-cleanup scheduler job.

  • Backend: New ActivityService with subscriber channels, snapshot/heartbeat SSE streaming, and per-environment history pruning integrated into the event cleanup job. All existing services now accept an *ActivityService dependency and emit start/append/complete lifecycle events.
  • Frontend: New activity-center component with real-time SSE consumption, activity list/detail views, and a settings page for retention configuration.
  • Database: Migration 050 adds the two tables with appropriate indexes for the primary query patterns (environment + status, resource, user).

Confidence Score: 4/5

Safe to merge with the concurrent-prune issue addressed; all other changes are additive and well-guarded.

StartPruneAll launches an unguarded background goroutine on every HTTP call. Back-to-back requests from the frontend will start multiple simultaneous Docker prune goroutines and create duplicate in-progress activity records. Everything else — the SSE streaming, activity CRUD, history pruning, and migration — looks correct and well-tested.

backend/internal/services/system_service.go — the StartPruneAll method needs a concurrency guard before merging.

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
backend/internal/services/system_service.go:94-108
**Concurrent prune goroutines not guarded**

`StartPruneAll` spawns an unguarded background goroutine on every call. If the endpoint is hit twice in quick succession, two goroutines will run simultaneously against the same Docker daemon, each creating its own activity record and competing for the same Docker resources (containers, images, volumes). The old synchronous `PruneAll` path naturally serialised these operations through the HTTP request lifecycle. The new background path has no such protection, so a rapid double-click from the frontend is enough to trigger two concurrent prune operations and confuse the activity feed with duplicate in-progress records.

Reviews (4): Last reviewed commit: "feat: full background activity tasks" | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

Copy link
Copy Markdown
Member Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@getarcaneappbot
Copy link
Copy Markdown
Contributor

getarcaneappbot commented Apr 24, 2026

Container images for this PR have been built successfully!

  • Manager: ghcr.io/getarcaneapp/arcane:pr-2434
  • Agent: ghcr.io/getarcaneapp/arcane-headless:pr-2434

Built from commit 6a43d22

@kmendell kmendell force-pushed the feat/activity-tasks branch 3 times, most recently from 335db97 to b969ae9 Compare April 25, 2026 06:24
@kmendell kmendell added this to the v1.19.0 milestone Apr 25, 2026
Comment thread tests/setup/global-setup.ts Dismissed
Comment thread tests/setup/global-setup.ts Dismissed
@kmendell kmendell force-pushed the feat/activity-tasks branch 2 times, most recently from b57eba7 to d045275 Compare April 26, 2026 18:13
@kmendell kmendell force-pushed the feat/activity-tasks branch from d045275 to 64a1b0b Compare April 26, 2026 20:55
@kmendell kmendell force-pushed the feat/activity-tasks branch from 64a1b0b to 0dfa0f3 Compare April 26, 2026 21:13
@getarcaneapp getarcaneapp deleted a comment from github-actions Bot Apr 26, 2026
@kmendell kmendell force-pushed the feat/activity-tasks branch 4 times, most recently from 415b25b to 6714dc2 Compare April 28, 2026 02:20
Comment thread backend/internal/huma/handlers/activities.go
Comment thread backend/internal/services/activity_service.go Outdated
Comment thread backend/internal/services/activity_service.go
@github-actions
Copy link
Copy Markdown

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

@github-actions
Copy link
Copy Markdown

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

@kmendell kmendell force-pushed the feat/activity-tasks branch 6 times, most recently from ba1550f to dc596d3 Compare April 29, 2026 22:47
@github-actions
Copy link
Copy Markdown

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

@kmendell kmendell force-pushed the feat/activity-tasks branch from dc596d3 to 4be88a2 Compare May 4, 2026 15:26
@kmendell kmendell force-pushed the feat/activity-tasks branch 5 times, most recently from 45bcfe4 to 1f17047 Compare May 6, 2026 04:27
Comment on lines 94 to 108
@@ -80,6 +103,7 @@ func (s *SystemService) PruneAll(ctx context.Context, req system.PruneAllRequest

if req.Images != nil && req.Images.Mode != system.PruneImageModeNone {
g.Go(func() error {
s.appendSystemPruneActivityMessageInternal(groupCtx, activityID, "Pruning images", 40)
slog.InfoContext(groupCtx, "Pruning images...", "mode", req.Images.Mode, "until", req.Images.Until)
localResult := &system.PruneAllResult{}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Concurrent prune goroutines not guarded

StartPruneAll spawns an unguarded background goroutine on every call. If the endpoint is hit twice in quick succession, two goroutines will run simultaneously against the same Docker daemon, each creating its own activity record and competing for the same Docker resources (containers, images, volumes). The old synchronous PruneAll path naturally serialised these operations through the HTTP request lifecycle. The new background path has no such protection, so a rapid double-click from the frontend is enough to trigger two concurrent prune operations and confuse the activity feed with duplicate in-progress records.

Prompt To Fix With AI
This is a comment left during a code review.
Path: backend/internal/services/system_service.go
Line: 94-108

Comment:
**Concurrent prune goroutines not guarded**

`StartPruneAll` spawns an unguarded background goroutine on every call. If the endpoint is hit twice in quick succession, two goroutines will run simultaneously against the same Docker daemon, each creating its own activity record and competing for the same Docker resources (containers, images, volumes). The old synchronous `PruneAll` path naturally serialised these operations through the HTTP request lifecycle. The new background path has no such protection, so a rapid double-click from the frontend is enough to trigger two concurrent prune operations and confuse the activity feed with duplicate in-progress records.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Codex Fix in Claude Code

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

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

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

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

@kmendell kmendell modified the milestones: v1.19.0, v1.20.0 May 8, 2026
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.

⚡️ Feature: Live background operations panel (for deploy, update, scans and download progress)

3 participants