Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e92868f
feat(tfc-job-agent): Init
zacharyblasczyk Feb 5, 2026
188ec1b
adding some tests
zacharyblasczyk Feb 5, 2026
7995dc8
Merge remote-tracking branch 'origin' into tfc-workspace-job-agent
zacharyblasczyk Feb 5, 2026
5435470
Merge remote-tracking branch 'origin' into tfc-workspace-job-agent
zacharyblasczyk Feb 9, 2026
29e6637
Merge remote-tracking branch 'origin' into tfc-workspace-job-agent
zacharyblasczyk Feb 9, 2026
cfad5e6
Merge remote-tracking branch 'origin' into tfc-workspace-job-agent
zacharyblasczyk Feb 9, 2026
057cd0a
Merge remote-tracking branch 'origin' into tfc-workspace-job-agent
zacharyblasczyk Feb 9, 2026
25f696d
Merge remote-tracking branch 'origin' into tfc-workspace-job-agent
zacharyblasczyk Feb 10, 2026
54aaf9c
Merge remote-tracking branch 'origin' into tfc-workspace-job-agent
zacharyblasczyk Feb 10, 2026
1aec52b
Merge remote-tracking branch 'origin' into tfc-workspace-job-agent
zacharyblasczyk Feb 10, 2026
b59d6ad
merge main
zacharyblasczyk Feb 18, 2026
6b834d7
Merge remote-tracking branch 'origin' into tfc-workspace-job-agent
zacharyblasczyk Feb 18, 2026
a18775c
Merge remote-tracking branch 'origin' into tfc-workspace-job-agent
zacharyblasczyk Feb 18, 2026
f79507c
Merge remote-tracking branch 'origin' into tfc-workspace-job-agent
zacharyblasczyk Feb 19, 2026
728ac9d
Merge remote-tracking branch 'origin' into tfc-workspace-job-agent
zacharyblasczyk Feb 19, 2026
282a8fe
Merge remote-tracking branch 'origin' into tfc-workspace-job-agent
zacharyblasczyk Feb 23, 2026
ffe9c72
Merge remote-tracking branch 'origin' into tfc-workspace-job-agent
zacharyblasczyk Feb 24, 2026
74cb732
Merge remote-tracking branch 'origin' into tfc-workspace-job-agent
zacharyblasczyk Feb 24, 2026
80900fd
refactor: TFE Job Agent
zacharyblasczyk Feb 25, 2026
eef077a
Merge remote-tracking branch 'origin' into tfc-workspace-job-agent
zacharyblasczyk Feb 25, 2026
80309dc
refactor
zacharyblasczyk Feb 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/workspace-engine/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@ctrlplane/workspace-engine",
"scripts": {
"dev": "air",
"build": "go build -o ./bin/workspace-engine main.go",
"build": "go build -o ./bin/workspace-engine .",
"lint": "bash -c 'golangci-lint run --allow-parallel-runners'",
"lint:fix": "golangci-lint run --fix",
"start": "./bin/workspace-engine",
Expand All @@ -11,4 +11,4 @@
"format": "bash -c 'go fmt ./...'",
"clean": "go clean ./..."
}
}
}
2 changes: 1 addition & 1 deletion apps/workspace-engine/pkg/reconcile/memory/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func (q *Queue) Enqueue(ctx context.Context, params reconcile.EnqueueParams) err
s.ClaimedBy = ""
s.ClaimedUntil = nil
}
if !(s.ClaimedUntil != nil && s.ClaimedUntil.After(now)) {
if s.ClaimedUntil == nil || !s.ClaimedUntil.After(now) {
s.UpdatedAt = now
}

Expand Down
55 changes: 55 additions & 0 deletions apps/workspace-engine/pkg/workspace/jobagents/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package jobagents
import (
"context"
"fmt"
"time"

"workspace-engine/pkg/oapi"
"workspace-engine/pkg/workspace/jobagents/argo"
Expand All @@ -12,6 +13,8 @@ import (
"workspace-engine/pkg/workspace/jobagents/types"
"workspace-engine/pkg/workspace/releasemanager/verification"
"workspace-engine/pkg/workspace/store"

"github.com/charmbracelet/log"
)

type Registry struct {
Expand All @@ -37,6 +40,58 @@ func (r *Registry) Register(dispatcher types.Dispatchable) {
r.dispatchers[dispatcher.Type()] = dispatcher
}

// RestoreJobs resumes tracking for all in-processing jobs after an engine restart.
// Dispatchers that implement Restorable get their jobs back; remaining orphaned
// jobs are failed.
func (r *Registry) RestoreJobs(ctx context.Context) {
allJobs := r.store.Jobs.Items()

// Collect in-processing jobs grouped by job agent type
jobsByType := make(map[string][]*oapi.Job)
for _, job := range allJobs {
if !job.IsInProcessingState() {
continue
}
agent, ok := r.store.JobAgents.Get(job.JobAgentId)
if !ok {
continue
}
jobsByType[agent.Type] = append(jobsByType[agent.Type], job)
}

if len(jobsByType) == 0 {
return
}

now := time.Now().UTC()
for agentType, jobs := range jobsByType {
dispatcher, ok := r.dispatchers[agentType]
if !ok {
continue
}

restorable, ok := dispatcher.(types.Restorable)
if ok {
log.Info("Restoring jobs for dispatcher", "type", agentType, "count", len(jobs))
if err := restorable.RestoreJobs(ctx, jobs); err != nil {
log.Error("Failed to restore jobs", "type", agentType, "error", err)
}
continue
}

// Non-restorable dispatcher: fail orphaned jobs
for _, job := range jobs {
message := "Job was in-progress when the engine restarted; dispatch goroutine lost"
job.Status = oapi.JobStatusFailure
job.Message = &message
job.CompletedAt = &now
job.UpdatedAt = now
r.store.Jobs.Upsert(ctx, job)
log.Info("Marked orphaned job as failed", "jobId", job.Id, "agentType", agentType)
}
}
}

func (r *Registry) Dispatch(ctx context.Context, job *oapi.Job) error {
jobAgent, ok := r.store.JobAgents.Get(job.JobAgentId)
if !ok {
Expand Down
Loading
Loading