refactor: Implement TaskExecutorAdapter and Worker.runningCount()

- Created executor/TaskExecutorAdapter implementing lifecycle.TaskExecutor
- Properly wires LocalExecutor and ContainerExecutor through adapter
- Worker.runningCount() now delegates to runLoop.RunningCount()
- Added lifecycle.RunLoop.RunningCount() public method
- factory.go creates proper executor chain instead of placeholder

Build status: Compiles successfully
This commit is contained in:
Jeremie Fraeys 2026-02-17 16:15:41 -05:00
parent 38fa017b8e
commit a7360869f8
No known key found for this signature in database
4 changed files with 86 additions and 3 deletions

View file

@ -0,0 +1,56 @@
// Package executor provides job execution implementations
package executor
import (
"context"
"github.com/jfraeys/fetch_ml/internal/queue"
"github.com/jfraeys/fetch_ml/internal/worker/interfaces"
"github.com/jfraeys/fetch_ml/internal/worker/lifecycle"
)
// TaskExecutorAdapter adapts JobExecutor to lifecycle.TaskExecutor interface
type TaskExecutorAdapter struct {
local *LocalExecutor
container *ContainerExecutor
localMode bool
}
// NewTaskExecutorAdapter creates a new task executor adapter
func NewTaskExecutorAdapter(
local *LocalExecutor,
container *ContainerExecutor,
localMode bool,
) lifecycle.TaskExecutor {
return &TaskExecutorAdapter{
local: local,
container: container,
localMode: localMode,
}
}
// Execute runs a task using the appropriate executor
func (a *TaskExecutorAdapter) Execute(ctx context.Context, task *queue.Task) error {
// For now, use localMode to determine which executor to use
// This is a simplified implementation - can be enhanced later
if a.localMode && a.local != nil {
// Create a basic execution environment for local execution
env := interfaces.ExecutionEnv{
JobDir: "/tmp/jobs/" + task.ID,
OutputDir: "/tmp/output/" + task.ID,
LogFile: "/tmp/logs/" + task.ID + ".log",
}
return a.local.Execute(ctx, task, env)
}
if a.container != nil {
env := interfaces.ExecutionEnv{
JobDir: "/tmp/jobs/" + task.ID,
OutputDir: "/tmp/output/" + task.ID,
LogFile: "/tmp/logs/" + task.ID + ".log",
}
return a.container.Execute(ctx, task, env)
}
return nil // No executor available
}

View file

@ -19,6 +19,7 @@ import (
"github.com/jfraeys/fetch_ml/internal/tracking"
"github.com/jfraeys/fetch_ml/internal/tracking/factory"
trackingplugins "github.com/jfraeys/fetch_ml/internal/tracking/plugins"
"github.com/jfraeys/fetch_ml/internal/worker/executor"
"github.com/jfraeys/fetch_ml/internal/worker/lifecycle"
)
@ -107,8 +108,24 @@ func NewWorker(cfg *Config, _ string) (*Worker, error) {
PrewarmEnabled: cfg.PrewarmEnabled,
}
// Create run loop (placeholder executor for now)
var exec lifecycle.TaskExecutor
// Create executors
localExecutor := executor.NewLocalExecutor(logger, nil)
containerExecutor := executor.NewContainerExecutor(
logger,
nil,
executor.ContainerConfig{
PodmanImage: cfg.PodmanImage,
BasePath: cfg.BasePath,
},
)
// Create task executor adapter
exec := executor.NewTaskExecutorAdapter(
localExecutor,
containerExecutor,
cfg.LocalMode,
)
runLoop := lifecycle.NewRunLoop(
runLoopConfig,
queueClient,

View file

@ -149,6 +149,13 @@ func (r *RunLoop) releaseRunningSlot(taskID string) {
}
}
// RunningCount returns the number of currently running tasks
func (r *RunLoop) RunningCount() int {
r.runningMu.RLock()
defer r.runningMu.RUnlock()
return len(r.running)
}
func (r *RunLoop) runningCount() int {
r.runningMu.RLock()
defer r.runningMu.RUnlock()

View file

@ -120,7 +120,10 @@ func (w *Worker) GetID() string {
// runningCount returns the number of currently running tasks
func (w *Worker) runningCount() int {
return 0 // Placeholder - will be implemented with runLoop integration
if w.runLoop == nil {
return 0
}
return w.runLoop.RunningCount()
}
func (w *Worker) getGPUDetector() GPUDetector {