diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 904204a..64f7ce8 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -29,6 +29,9 @@ jobs: - name: Test run: go test -v ./... + - name: Run coverage + run: go test -race -coverprofile=coverage.txt -covermode=atomic ./... + - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v4.0.1 diff --git a/status.go b/status.go index 05d2e4e..3de5b68 100644 --- a/status.go +++ b/status.go @@ -5,6 +5,7 @@ import ( "time" ) +// Status represents the status of the job. type Status struct { Timestamp string `json:"timestamp"` NumFailed int64 `json:"num_failed"` @@ -31,12 +32,22 @@ func newStatusManager() *statusManager { } } +func (sm *statusManager) notify() { + status := sm.Snapshot() + for _, ch := range sm.statusChans { + ch <- status + } +} + +// Start starts the status manager. +// It will notify all the status channels every second. func (sm *statusManager) Start() { for range sm.ticker.C { sm.notify() } } +// Stop stops the status manager. func (sm *statusManager) Stop() { sm.notify() sm.ticker.Stop() @@ -45,32 +56,43 @@ func (sm *statusManager) Stop() { } } +// IncFailed increments the number of failed jobs. func (sm *statusManager) IncFailed() { sm.mutex.Lock() sm.numFailed++ sm.mutex.Unlock() } +// IncSucceed increments the number of succeed jobs. func (sm *statusManager) IncSucceed() { sm.mutex.Lock() sm.numSucceed++ sm.mutex.Unlock() } +// SetTotal sets the total number of jobs. +// It should be called before the job starts. func (sm *statusManager) SetTotal(total int64) { sm.mutex.Lock() sm.numTotal = total sm.mutex.Unlock() } +// StatusChan returns a channel that will receive the status of the job. +// The status will be sent every second. It should be called before the job starts. +// You can call it multiple times to get multiple channels. func (sm *statusManager) StatusChan() <-chan Status { ch := make(chan Status) sm.statusChans = append(sm.statusChans, ch) return ch } +// Snapshot returns the current status of the job. func (sm *statusManager) Snapshot() Status { - sm.mutex.Lock() + defer func() func() { + sm.mutex.Lock() + return func() { sm.mutex.Unlock() } + }()() status := Status{ Timestamp: time.Now().Format(time.RFC3339), NumFailed: sm.numFailed, @@ -78,13 +100,5 @@ func (sm *statusManager) Snapshot() Status { NumFinished: sm.numFailed + sm.numSucceed, NumTotal: sm.numTotal, } - sm.mutex.Unlock() return status } - -func (sm *statusManager) notify() { - status := sm.Snapshot() - for _, ch := range sm.statusChans { - ch <- status - } -}