diff --git a/database-8_test.go b/database-8_test.go new file mode 100644 index 0000000000000000000000000000000000000000..dfaa323ad4db1f904765a7ec1df74a4a6807d804 --- /dev/null +++ b/database-8_test.go @@ -0,0 +1,104 @@ +// Copyright 2024 schukai GmbH +// SPDX-License-Identifier: AGPL-3.0 + +package jobqueue + +import ( + "github.com/stretchr/testify/assert" + "gorm.io/driver/sqlite" + "gorm.io/gorm" + "gorm.io/gorm/logger" + "log" + "os" + "testing" + "time" +) + +func TestUpdateJob(t *testing.T) { + db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) + assert.NoError(t, err) + + assert.NoError(t, db.AutoMigrate(&JobPersistence{}, &JobLog{}, &JobStats{})) + + runner := &CounterRunnable{} + job := NewJob[CounterResult]("job1", runner) + assert.NoError(t, saveJob(job, db)) + + job.SetPriority(PriorityHigh) + assert.NoError(t, updateJob(job, db)) + + var jobPersistence JobPersistence + assert.NoError(t, db.First(&jobPersistence, "id = ?", job.GetID()).Error) + assert.Equal(t, PriorityDefault, jobPersistence.Priority) // PriorityDefault because the update should not update the priority + + assert.NoError(t, saveJob(job, db)) + + assert.NoError(t, db.First(&jobPersistence, "id = ?", job.GetID()).Error) + assert.Equal(t, PriorityHigh, jobPersistence.Priority) + + var count int64 + db.Model(&JobPersistence{}).Count(&count) + assert.Equal(t, int64(1), count) // Nur ein Datensatz sollte vorhanden sein +} + +func TestCheckAndSaveOrUpdate(t *testing.T) { + + newLogger := logger.New( + log.New(os.Stdout, "\r\n", log.LstdFlags), + logger.Config{ + SlowThreshold: time.Second, + LogLevel: logger.Info, + Colorful: true, + }, + ) + + db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{ + Logger: newLogger, + }) + assert.NoError(t, err) + + assert.NoError(t, db.AutoMigrate(&JobPersistence{}, &JobLog{}, &JobStats{})) + + runner := &CounterRunnable{} + job := NewJob[CounterResult]("job1", runner) + + syncer := &JobSyncer{manager: &Manager{database: db}} + + var jobPersistence JobPersistence + + assert.NoError(t, syncer.CheckAndSaveOrUpdate(job)) + jobPersistence = JobPersistence{} + assert.NoError(t, db.First(&jobPersistence, "id = ?", job.GetID()).Error) + assert.Equal(t, PriorityDefault, jobPersistence.Priority) + + job.SetPriority(PriorityHigh) + assert.NoError(t, syncer.CheckAndSaveOrUpdate(job)) + jobPersistence = JobPersistence{} + assert.NoError(t, db.First(&jobPersistence, "id = ?", job.GetID()).Error) + assert.Equal(t, PriorityDefault, jobPersistence.Priority) // second update should not update the priority, because update only update stats and logs + + // set stats and logs and test + job.stats = JobStats{ + JobID: job.GetID(), + RunCount: 2, + SuccessCount: 3, + ErrorCount: 4, + TimeMetrics: TimeMetrics{}, + CreatedAt: time.Time{}, + UpdatedAt: time.Time{}, + DeletedAt: gorm.DeletedAt{}, + } + + job.logs = []JobLog{ + { + JobID: job.GetID(), + }} + + assert.NoError(t, syncer.CheckAndSaveOrUpdate(job)) + + job.stats.RunCount = 9 + assert.NoError(t, syncer.CheckAndSaveOrUpdate(job)) + + jobPersistence = JobPersistence{} + assert.NoError(t, db.First(&jobPersistence, "id = ?", job.GetID()).Error) +} diff --git a/database.go b/database.go index 5cb3ed1434a4ec42d7e30ecd1317edd74e674e3e..6ce44a0bc70a291cfcaf1b7d261b953ca377cd86 100644 --- a/database.go +++ b/database.go @@ -4,11 +4,37 @@ package jobqueue import ( + "errors" "gorm.io/gorm" "strings" "time" ) +func (s *JobSyncer) CheckAndSaveOrUpdate(job GenericJob) error { + s.mu.Lock() + defer s.mu.Unlock() + + if s.manager == nil || s.manager.database == nil { + return ErrNoDatabaseConnection + } + + permJob := job.GetPersistence() + db := s.manager.database + + var existing JobPersistence + result := db.Where("id = ?", permJob.ID).First(&existing) + + if result.Error == nil { + return updateJob(job, db) + } + + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return saveJob(job, db) + } + + return result.Error +} + func (s *JobSyncer) DeleteJob(job GenericJob) error { s.mu.Lock() defer s.mu.Unlock() @@ -63,13 +89,72 @@ func (s *JobSyncer) ResetStats(job GenericJob) error { return ErrNoDatabaseConnection } return saveJob(job, s.manager.database) - //stats := job.GetStats() - //return s.manager.database.Transaction(func(tx *gorm.DB) error { - // return tx.Model(&JobStats{}).Where("job_id = ?", - // job.GetID()). - // Select("*").Omit("deleted_at", "created_at", "job_id").Updates(stats).Error - // - //}) + +} + +func (s *JobSyncer) UpdateJob(job GenericJob) error { + s.mu.Lock() + defer s.mu.Unlock() + if s.manager == nil || s.manager.database == nil { + return ErrNoDatabaseConnection + } + return updateJob(job, s.manager.database) +} + +func updateJob(job GenericJob, db *gorm.DB) error { + + if db == nil { + return ErrNoDatabaseConnection + } + + permJob := job.GetPersistence() + + maxRetries := 3 + var attempt int + for attempt = 0; attempt < maxRetries; attempt++ { + err := update(&permJob, db) + if err != nil { + if strings.Contains(err.Error(), "lock") { + time.Sleep(time.Millisecond * 100) + continue + } + return err + } + break + } + + if attempt == maxRetries { + return ErrMaxRetriesReached + } + + return nil + +} + +func update(job *JobPersistence, db *gorm.DB) error { + + if db == nil { + return ErrNoDatabaseConnection + } + + permJob := job.GetPersistence() + + return db.Transaction(func(tx *gorm.DB) error { + + if permJob.Stats != (JobStats{}) { + if err := tx.Model(&permJob).Select("Stats").Updates(map[string]interface{}{"stats": permJob.Stats}).Error; err != nil { + return err + } + } + + for i, _ := range job.Logs { + job.Logs[i].LogID = 0 + _ = tx.Create(&job.Logs[i]) + // no error handling, if it fails, it fails + } + + return nil + }) } func (s *JobSyncer) SaveJob(job GenericJob) error { @@ -138,94 +223,4 @@ func saveJob(job GenericJob, db *gorm.DB) error { return nil - //return db.Transaction(func(tx *gorm.DB) error { - // - // permJob := job.GetPersistence() - // - // memLogs := permJob.Logs - // permJob.Logs = nil - // - // var existingJob JobPersistence - // result := tx.Unscoped().Where("id = ?", permJob.GetID()).First(&existingJob) - // - // if result.Error != nil { - // err, done := createJob(tx, result, permJob) - // if done { - // return err - // } - // } else { - // - // err, done := updateJob(tx, existingJob, permJob) - // if done { - // return err - // } - // } - // - // if tx.Error != nil { - // Trace("Error while updating job", "error", tx.Error) - // return tx.Error - // } - // - // return nil - // - //}) - } - -// -//func updateJob(tx *gorm.DB, existingJob JobPersistence, permJob JobPersistence) (error, bool) { -// -// r := tx.Unscoped().Model(&existingJob).Select("*"). -// Omit("deleted_at", "created_at", "job_id"). -// Update("deleted_at", nil) -// -// if r.Error != nil { -// Trace("Error while deleting job", "error", r.Error) -// return r.Error, true -// } -// -// resultStats := tx.Model(&existingJob).Select("*"). -// Omit("deleted_at", "created_at", "job_id").Update() -// -// if resultStats.Error != nil { -// Trace("Error while updating job stats", "error", resultStats.Error) -// return resultStats.Error, true -// } -// -// r2 := tx.Model(&existingJob).Select("*"). -// Omit("deleted_at", "created_at", "job_id").Updates(permJob) -// if r2.Error != nil { -// return r2.Error, true -// } -// -// tx.Model(&permJob.Stats). -// Select("*").Omit("deleted_at", "created_at", "job_id"). -// UpdateColumns(permJob.Stats) -// -// if tx.Error != nil { -// Error("Error while updating job stats", "error", tx.Error) -// return result.Error -// } -// -// for i, _ := range memLogs { -// memLogs[i].LogID = 0 -// _ = tx.Create(&memLogs[i]) -// // no error handling, if it fails, it fails -// } -// -// return nil, false -//} -// -//func createJob(tx *gorm.DB, result *gorm.DB, permJob JobPersistence) (error, bool) { -// if errors.Is(result.Error, gorm.ErrRecordNotFound) { -// err := tx.Create(&permJob).Error -// if err != nil { -// Trace("Error while creating job", "error", err) -// return err, true -// } -// } else { -// Trace("Error while creating job", "error", result.Error) -// return result.Error, true -// } -// return nil, false -//} diff --git a/devenv.lock b/devenv.lock index 6b47afb1fd265375d548fa1e63cb09538c404a1d..6414869260904261550a6b0a94e2d5da55f2479c 100644 --- a/devenv.lock +++ b/devenv.lock @@ -3,11 +3,11 @@ "devenv": { "locked": { "dir": "src/modules", - "lastModified": 1710144971, - "narHash": "sha256-CjTOdoBvT/4AQncTL20SDHyJNgsXZjtGbz62yDIUYnM=", + "lastModified": 1713353943, + "narHash": "sha256-1gDYT+Hhqpnt+CDYL1h2huE07c6BCod6qlsaFNTPcn8=", "owner": "cachix", "repo": "devenv", - "rev": "6c0bad0045f1e1802f769f7890f6a59504825f4d", + "rev": "5b933eb8522b61873e859c9c68de16330d8f5d8b", "type": "github" }, "original": { @@ -38,11 +38,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1701680307, - "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", "type": "github" }, "original": { @@ -59,11 +59,11 @@ ] }, "locked": { - "lastModified": 1703887061, - "narHash": "sha256-gGPa9qWNc6eCXT/+Z5/zMkyYOuRZqeFZBDbopNZQkuY=", + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", "owner": "hercules-ci", "repo": "gitignore.nix", - "rev": "43e1aa1308018f37118e34d3a9cb4f5e75dc11d5", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", "type": "github" }, "original": { @@ -74,11 +74,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1710695816, - "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=", + "lastModified": 1713145326, + "narHash": "sha256-m7+IWM6mkWOg22EC5kRUFCycXsXLSU7hWmHdmBfmC3s=", "owner": "nixos", "repo": "nixpkgs", - "rev": "614b4613980a522ba49f0d194531beddbb7220d3", + "rev": "53a2c32bc66f5ae41a28d7a9a49d321172af621e", "type": "github" }, "original": { @@ -90,11 +90,11 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1704874635, - "narHash": "sha256-YWuCrtsty5vVZvu+7BchAxmcYzTMfolSPP5io8+WYCg=", + "lastModified": 1710695816, + "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "3dc440faeee9e889fe2d1b4d25ad0f430d449356", + "rev": "614b4613980a522ba49f0d194531beddbb7220d3", "type": "github" }, "original": { @@ -106,11 +106,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1710695816, - "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=", + "lastModified": 1713145326, + "narHash": "sha256-m7+IWM6mkWOg22EC5kRUFCycXsXLSU7hWmHdmBfmC3s=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "614b4613980a522ba49f0d194531beddbb7220d3", + "rev": "53a2c32bc66f5ae41a28d7a9a49d321172af621e", "type": "github" }, "original": { @@ -130,11 +130,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1708018599, - "narHash": "sha256-M+Ng6+SePmA8g06CmUZWi1AjG2tFBX9WCXElBHEKnyM=", + "lastModified": 1712897695, + "narHash": "sha256-nMirxrGteNAl9sWiOhoN5tIHyjBbVi5e2tgZUgZlK3Y=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "5df5a70ad7575f6601d91f0efec95dd9bc619431", + "rev": "40e6053ecb65fcbf12863338a6dcefb3f55f1bf8", "type": "github" }, "original": { diff --git a/event-bus.go b/event-bus.go index 4038de7755732476d0b6666456ea0b6140c59a98..8715b4ed834bb205666d50c93734cd8b4271f4e6 100644 --- a/event-bus.go +++ b/event-bus.go @@ -50,6 +50,7 @@ type EventBus struct { // NewEventBus creates a new event bus func NewEventBus() *EventBus { + Info("EventBus created") return &EventBus{ subscribers: make(map[EventName][]chan interface{}), publishErr: make(map[MessageID]error), @@ -60,6 +61,7 @@ func NewEventBus() *EventBus { func (eb *EventBus) Shutdown() { close(eb.shutdownChan) eb.wg.Wait() + Info("EventBus shutdown") } // Subscribe adds a channel to the subscribers list @@ -111,6 +113,8 @@ func (eb *EventBus) Publish(name EventName, data any) { eb.mu.RLock() defer eb.mu.RUnlock() + Info("EventBus: publishing event %s", name) + select { case <-eb.shutdownChan: return diff --git a/go.mod b/go.mod index 6baeff1dcb6d38f7dd8f3aeb4ed8ac21802b41d5..2164807e9c4ce55570d1138773b41febadd33e2f 100644 --- a/go.mod +++ b/go.mod @@ -7,17 +7,17 @@ require ( github.com/docker/docker v24.0.6+incompatible github.com/docker/go-connections v0.4.0 github.com/fsnotify/fsnotify v1.7.0 - github.com/go-chi/chi/v5 v5.0.10 github.com/google/uuid v1.6.0 github.com/pkg/sftp v1.13.6 github.com/robfig/cron/v3 v3.0.1 - github.com/shirou/gopsutil/v3 v3.24.2 - github.com/stretchr/testify v1.8.4 + github.com/shirou/gopsutil/v3 v3.24.3 + github.com/stretchr/testify v1.9.0 go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.21.0 + golang.org/x/crypto v0.22.0 gopkg.in/yaml.v3 v3.0.1 - gorm.io/driver/mysql v1.5.5 - gorm.io/gorm v1.25.8 + gorm.io/driver/mysql v1.5.6 + gorm.io/driver/sqlite v1.5.5 + gorm.io/gorm v1.25.9 ) require ( @@ -28,12 +28,12 @@ require ( github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/go-units v0.5.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/go-sql-driver/mysql v1.8.0 // indirect + github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/kr/fs v0.1.0 // indirect - github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a // indirect + github.com/lufia/plan9stats v0.0.0-20240408141607-282e7b5d6b74 // indirect github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect @@ -49,9 +49,8 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/mod v0.8.0 // indirect golang.org/x/net v0.21.0 // indirect - golang.org/x/sys v0.18.0 // indirect + golang.org/x/sys v0.19.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.6.0 // indirect - gorm.io/driver/sqlite v1.5.5 // indirect gotest.tools/v3 v3.5.1 // indirect ) diff --git a/go.sum b/go.sum index 03a350f93722601728cec9f6e0ac5faec79e81d1..8821dbc76ef3d3ad669d25e3cc948ea26f11e9cc 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,5 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= @@ -20,26 +19,17 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= -github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= -github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/go-sql-driver/mysql v1.8.0 h1:UtktXaU2Nb64z/pLiGIxY4431SJ4/dR5cjMmlVHgnT4= -github.com/go-sql-driver/mysql v1.8.0/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -51,15 +41,11 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= -github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed h1:036IscGBfJsFIgJQzlui7nK1Ncm0tp2ktmPj8xO4N/0= -github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= -github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a h1:3Bm7EwfUQUvhNeKIkUct/gl9eod1TcXuj8stxvi/GoI= -github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= +github.com/lufia/plan9stats v0.0.0-20240408141607-282e7b5d6b74 h1:1KuuSOy4ZNgW0KA2oYIngXVFhQcXxhLqCVK7cBcldkk= +github.com/lufia/plan9stats v0.0.0-20240408141607-282e7b5d6b74/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -72,52 +58,37 @@ github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Q github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig= -github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= -github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= -github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM= -github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE= -github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ= -github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= -github.com/shirou/gopsutil/v3 v3.24.2 h1:kcR0erMbLg5/3LcInpw0X/rrPSqq4CDPyI6A6ZRC18Y= -github.com/shirou/gopsutil/v3 v3.24.2/go.mod h1:tSg/594BcA+8UdQU2XcW803GWYgdtauFFPgJCJKZlVk= +github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE= +github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= -github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= -github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= -github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -125,14 +96,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -145,15 +110,12 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -166,27 +128,16 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -199,26 +150,17 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs= -gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8= -gorm.io/driver/mysql v1.5.4 h1:igQmHfKcbaTVyAIHNhhB888vvxh8EdQ2uSUT0LPcBso= -gorm.io/driver/mysql v1.5.4/go.mod h1:9rYxJph/u9SWkWc9yY4XJ1F/+xO0S/ChOmbk3+Z5Tvs= -gorm.io/driver/mysql v1.5.5 h1:WxklwX6FozMs1gk9yVadxGfjGiJjrBKPvIIvYZOMyws= -gorm.io/driver/mysql v1.5.5/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8= +gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= gorm.io/driver/sqlite v1.5.5 h1:7MDMtUZhV065SilG62E0MquljeArQZNfJnjd9i9gx3E= gorm.io/driver/sqlite v1.5.5/go.mod h1:6NgQ7sQWAIFsPrJJl1lSNSu2TABh0ZZ/zm5fosATavE= -gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= -gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= -gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= -gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A= gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gorm.io/gorm v1.25.8 h1:WAGEZ/aEcznN4D03laj8DKnehe1e9gYQAjW8xyPRdeo= gorm.io/gorm v1.25.8/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= -gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gorm.io/gorm v1.25.9 h1:wct0gxZIELDk8+ZqF/MVnHLkA1rvYlBWUMv2EdsK1g8= +gorm.io/gorm v1.25.9/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= diff --git a/job-syncer.go b/job-syncer.go index 488569dd80e7ac42beb982807ceafd90831251cb..57b453557f4dcd80ed46adb8fad54710714efdd0 100644 --- a/job-syncer.go +++ b/job-syncer.go @@ -38,6 +38,7 @@ func NewJobSyncer(manager *Manager) *JobSyncer { return js } + func (js *JobSyncer) Wait(timeout time.Duration) error { done := make(chan struct{}) @@ -62,7 +63,8 @@ func (js *JobSyncer) Sync(job GenericJob) { js.running.Add(1) go func() { defer js.running.Done() - err := saveJob(job, js.manager.GetDB()) + + err := js.CheckAndSaveOrUpdate(job) if err != nil { Error("Error while creating or updating job", err) } diff --git a/manager.go b/manager.go index 6270407e8eb6a1cd64fa80304da0b46cc1505142..cc5f5d1e7e602e5bcf627df06ecd274d3c10e7b4 100644 --- a/manager.go +++ b/manager.go @@ -537,6 +537,7 @@ func (m *Manager) RunJob(job GenericJob) error { } if !job.IsPaused() { + Info("Job queued", "job_id", job.GetID()) m.eventBus.Publish(QueueJob, job) } diff --git a/persistence.go b/persistence.go index 1c33f8dba21c094c09b6c5b29104794f2052095f..ea0c8a61eb54c7787705a2478a61ef7737c3e986 100644 --- a/persistence.go +++ b/persistence.go @@ -132,7 +132,9 @@ func ReadYAMLFile(filePath string) ([]JobPersistence, error) { if err != nil { return nil, err } - defer file.Close() + defer func() { + _ = file.Close() + }() return ReadYAML(file) } @@ -142,7 +144,9 @@ func ReadJsonFile(filePath string) ([]JobPersistence, error) { if err != nil { return nil, err } - defer file.Close() + defer func() { + _ = file.Close() + }() return ReadJSON(file) } diff --git a/runnable-shell.go b/runnable-shell.go index 2d2c54d868c49e1a7ea540f19b50c10d5be95bef..9909c22e457a58c808ec22b1c6332baf683c0a92 100644 --- a/runnable-shell.go +++ b/runnable-shell.go @@ -63,6 +63,7 @@ func (s *ShellRunnable) Run(ctx context.Context) (RunResult[ShellResult], error) // write to temp tmp, err := os.CreateTemp("", "script-*.sh") if err != nil { + Error("Failed to create temp file: %v", err) return RunResult[ShellResult]{ Status: ResultStatusFailed, Data: ShellResult{ @@ -74,11 +75,16 @@ func (s *ShellRunnable) Run(ctx context.Context) (RunResult[ShellResult], error) } scriptPath = tmp.Name() - defer os.Remove(scriptPath) + defer func() { + _ = os.Remove(scriptPath) + }() _, err = tmp.WriteString(s.Script) - defer tmp.Close() + defer func() { + _ = tmp.Close() + }() if err != nil { + Error("Failed to write temp file: %v", err) return RunResult[ShellResult]{ Status: ResultStatusFailed, Data: ShellResult{ @@ -97,6 +103,7 @@ func (s *ShellRunnable) Run(ctx context.Context) (RunResult[ShellResult], error) var stderr []byte if err != nil { + Error("Failed to run script: %v", err) stderr = err.(*exec.ExitError).Stderr } @@ -106,6 +113,9 @@ func (s *ShellRunnable) Run(ctx context.Context) (RunResult[ShellResult], error) if exitError, ok := err.(*exec.ExitError); ok { exitCode = exitError.ExitCode() } + + Error("Failed to run script: %v", err) + return RunResult[ShellResult]{ Status: ResultStatusFailed, Data: ShellResult{ diff --git a/scheduler-event.go b/scheduler-event.go index e5b8343e003eefb5c37e218e30fbf3c770b29f6e..b295e1e78d6088b791b6d98be5890eedee98ace6 100644 --- a/scheduler-event.go +++ b/scheduler-event.go @@ -38,6 +38,7 @@ func (s *EventScheduler) Schedule(job GenericJob, eventBus *EventBus) error { select { case <-ch: if !job.IsPaused() { + Info("EventScheduler: received event %s, scheduling job %s", s.Event, id) eventBus.Publish(QueueJob, job) } case <-stopChan: diff --git a/scheduler_test.go b/scheduler_test.go index 682292da47b66a30050881cf22e89747d61dbece..40a81dbc71302ef5b12e5eca976d292a5c43cbe7 100644 --- a/scheduler_test.go +++ b/scheduler_test.go @@ -265,7 +265,7 @@ func TestEventScheduler_BasicFunctionality(t *testing.T) { time.Sleep(time.Millisecond * 50) // Allow some time for the event to propagate if atomic.LoadInt32(&count) != 1 { - t.Errorf("Expected to run 1 time, ran %d times", count) + t.Errorf("Expected to run one time, ran %d times", count) } } @@ -414,7 +414,7 @@ func TestInotifyScheduler_BasicFunctionality(t *testing.T) { } func TestUnmarshalSchedulerPersistenceYAML(t *testing.T) { - // Beispiel-YAML-Daten + // Test unmarshalling of a YAML string into a SchedulerPersistence struct yamlData := ` type: interval interval: 1m @@ -428,7 +428,6 @@ time: "2023-12-15T12:00:00Z" expectedInterval, _ := time.ParseDuration("1m") expectedTime, _ := time.Parse(time.RFC3339, "2023-12-15T12:00:00Z") - // Prüfen, ob die Werte korrekt unmarshalled wurden assert.Equal(t, "interval", sp.Type, "Type should be unmarshalled correctly") assert.Equal(t, expectedInterval, sp.Interval, "Interval should be unmarshalled correctly") assert.Equal(t, &expectedTime, sp.Time, "Time should be unmarshalled correctly")