Skip to content

Commit

Permalink
feat: improve error handling and introduce analysis cancellation support
Browse files Browse the repository at this point in the history
- Added a new error type, ErrAnalysisCanceled, to handle user-initiated cancellations during audio analysis.
- Updated error handling in main.go and directory.go to utilize the new error type for clearer cancellation feedback.
- Enhanced synchronization in file.go to ensure safe access to processing errors across goroutines.

These changes enhance the robustness of audio processing by providing clearer error reporting and supporting graceful cancellation of analysis tasks.
  • Loading branch information
tphakala committed Jan 19, 2025
1 parent 04ff386 commit 5ac258d
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 7 deletions.
5 changes: 3 additions & 2 deletions internal/analysis/directory.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package analysis
import (
"context"
"encoding/binary"
"errors"
"fmt"
"log"
"math/rand"
Expand Down Expand Up @@ -383,9 +384,9 @@ func DirectoryAnalysis(settings *conf.Settings) error {
}

if analysisErr != nil {
if analysisErr == context.Canceled {
if errors.Is(analysisErr, context.Canceled) {
log.Printf("Analysis of file '%s' was interrupted", path)
return false, nil
return false, ErrAnalysisCanceled
}
return false, fmt.Errorf("error analyzing file '%s': %w", path, analysisErr)
}
Expand Down
6 changes: 6 additions & 0 deletions internal/analysis/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package analysis

import "errors"

// ErrAnalysisCanceled is returned when the analysis is canceled by the user
var ErrAnalysisCanceled = errors.New("analysis canceled")
23 changes: 19 additions & 4 deletions internal/analysis/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"strings"
"sync"
"time"

"github.com/tphakala/birdnet-go/internal/birdnet"
Expand Down Expand Up @@ -249,14 +250,18 @@ func processAudioFile(settings *conf.Settings, audioInfo *myaudio.AudioInfo, ctx

// Start result collector goroutine
var processingError error
var processingErrorMutex sync.Mutex

go func() {
if settings.Debug {
fmt.Println("DEBUG: Result collector started")
}
for i := 1; i <= totalChunks; i++ {
select {
case <-ctx.Done():
processingErrorMutex.Lock()
processingError = ctx.Err()
processingErrorMutex.Unlock()
close(doneChan)
return
case notes := <-resultChan:
Expand All @@ -269,14 +274,18 @@ func processAudioFile(settings *conf.Settings, audioInfo *myaudio.AudioInfo, ctx
if settings.Debug {
fmt.Printf("DEBUG: Collector received error: %v\n", err)
}
processingErrorMutex.Lock()
processingError = err
processingErrorMutex.Unlock()
close(doneChan)
return
case <-time.After(5 * time.Second):
if settings.Debug {
fmt.Printf("DEBUG: Timeout waiting for chunk %d results\n", i)
}
processingErrorMutex.Lock()
processingError = fmt.Errorf("timeout waiting for analysis results (processed %d/%d chunks)", chunkCount, totalChunks)
processingErrorMutex.Unlock()
close(doneChan)
return
}
Expand Down Expand Up @@ -305,7 +314,10 @@ func processAudioFile(settings *conf.Settings, audioInfo *myaudio.AudioInfo, ctx
filePosition = filePosition.Add(time.Duration((3.0 - bn.Settings.BirdNET.Overlap) * float64(time.Second)))
return nil
case <-doneChan:
return processingError
processingErrorMutex.Lock()
err := processingError
processingErrorMutex.Unlock()
return err
case <-time.After(5 * time.Second):
return fmt.Errorf("timeout sending chunk to processing")
}
Expand All @@ -328,11 +340,14 @@ func processAudioFile(settings *conf.Settings, audioInfo *myaudio.AudioInfo, ctx
return nil, fmt.Errorf("error processing audio: %w", err)
}

if processingError != nil {
processingErrorMutex.Lock()
err = processingError
processingErrorMutex.Unlock()
if err != nil {
if settings.Debug {
fmt.Printf("DEBUG: Processing error encountered: %v\n", processingError)
fmt.Printf("DEBUG: Processing error encountered: %v\n", err)
}
return allNotes, processingError
return allNotes, err
}

if settings.Debug {
Expand Down
4 changes: 3 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package main

import (
"embed"
"errors"
"fmt"
"os"
"runtime/pprof"
"time"

"github.com/spf13/viper"
"github.com/tphakala/birdnet-go/cmd"
"github.com/tphakala/birdnet-go/internal/analysis"
"github.com/tphakala/birdnet-go/internal/conf"
"github.com/tphakala/birdnet-go/internal/httpcontroller"
)
Expand Down Expand Up @@ -68,7 +70,7 @@ func main() {
// Execute the root command
rootCmd := cmd.RootCommand(settings)
if err := rootCmd.Execute(); err != nil {
if err.Error() == "error processing audio: context canceled" {
if errors.Is(err, analysis.ErrAnalysisCanceled) {
// Clean exit for user-initiated cancellation
os.Exit(0)
}
Expand Down

0 comments on commit 5ac258d

Please sign in to comment.