Files
aptly/task/task.go
T
André Roth 4445839adc tasks: fix task state locking
Race condition iexisted where task State, err, and processReturnValue fields
were written by consumer goroutine and read by concurrent accessors without
proper synchronization, causing torn reads and data races.

Implemented single-lock model with optimal lock scope:

- Removed 8 accessor methods (direct field access is simpler)
- Lock only during brief state transitions (IDLE→RUNNING, RUNNING→SUCCEEDED/FAILED)
- Release lock during task.process() execution to enable full concurrency
- Readers hold list.Lock() only during atomic struct copy
- Moved State = RUNNING before goroutine spawn for clearer semantics
- task/list.go: RunTaskInBackground() copies *task before unlock,
    returns the pre-made copy instead of dereferencing after unlock
2026-06-07 23:47:09 +02:00

73 lines
1.5 KiB
Go

package task
import (
"sync"
"sync/atomic"
"github.com/aptly-dev/aptly/aptly"
)
// State task is in
type State int
// Detail represents custom task details
type Detail struct {
atomic.Value
}
// PublishDetail represents publish task details
type PublishDetail struct {
*Detail
TotalNumberOfPackages int64
RemainingNumberOfPackages int64
}
type ProcessReturnValue struct {
Code int
Value interface{}
}
// Process is a function implementing the actual task logic
type Process func(out aptly.Progress, detail *Detail) (*ProcessReturnValue, error)
const (
// IDLE when task is waiting
IDLE State = iota
// RUNNING when task is running
RUNNING
// SUCCEEDED when task is successfully finished
SUCCEEDED
// FAILED when task failed
FAILED
)
// Task represents as task in a queue encapsulates process code
// All fields are protected by List.Mutex - access task fields only while holding list.Lock()
type Task struct {
output *Output
detail *Detail
process Process
processReturnValue *ProcessReturnValue
err error
Name string
ID int
State State
resources []string
wgTask *sync.WaitGroup
}
// NewTask creates new task
func NewTask(process Process, name string, ID int, resources []string, wgTask *sync.WaitGroup) *Task {
task := &Task{
output: NewOutput(),
detail: &Detail{},
process: process,
Name: name,
ID: ID,
State: IDLE,
resources: resources,
wgTask: wgTask,
}
return task
}