Skip to content

Commit

Permalink
Feat/remove unused triggers (#1033)
Browse files Browse the repository at this point in the history
  • Loading branch information
kissken authored Jun 20, 2024
1 parent 78a7a88 commit fbd7e35
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 10 deletions.
13 changes: 13 additions & 0 deletions cmd/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
logging "github.com/moira-alert/moira/logging/zerolog_adapter"
"github.com/moira-alert/moira/support"
_ "go.uber.org/automaxprocs"

"github.com/xiam/to"
)

// Moira version.
Expand Down Expand Up @@ -71,6 +73,7 @@ var (
var (
removeTriggersStartWith = flag.String("remove-triggers-start-with", "", "Remove triggers which have ID starting with string parameter")
removeUnusedTriggersStartWith = flag.String("remove-unused-triggers-start-with", "", "Remove unused triggers which have ID starting with string parameter")
removeUnusedTriggersWithTTL = flag.String("remove-unused-triggers-with-ttl", "", "Remove unused triggers which have no subscription and no modify more that duration")
)

func main() { //nolint
Expand Down Expand Up @@ -213,6 +216,16 @@ func main() { //nolint
}
}

if *removeUnusedTriggersWithTTL != "" {
log := logger.String(moira.LogFieldNameContext, "remove-unused-triggers-with-ttl")
ttl := int64(to.Duration(*removeUnusedTriggersWithTTL).Seconds())
if err := handleRemoveUnusedTriggersWithTTL(logger, database, ttl); err != nil {
log.Error().
Error(err).
Msg("Failed to remove unused triggers with ttl")
}
}

if *cleanupUsers {
log := logger.String(moira.LogFieldNameContext, "cleanup-users")

Expand Down
49 changes: 41 additions & 8 deletions cmd/cli/triggers.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func handleRemoveTriggersStartWith(logger moira.Logger, database moira.Database,
return fmt.Errorf("can't get trigger IDs start with prefix %s: %w", prefix, err)
}

return deleteTriggers(logger, triggers, prefix, database)
return deleteTriggers(logger, triggers, database)
}

func handleRemoveUnusedTriggersStartWith(logger moira.Logger, database moira.Database, prefix string) error {
Expand All @@ -41,21 +41,55 @@ func handleRemoveUnusedTriggersStartWith(logger moira.Logger, database moira.Dat
}
}

return deleteTriggers(logger, triggersToDelete, prefix, database)
return deleteTriggers(logger, triggersToDelete, database)
}

func deleteTriggers(logger moira.Logger, triggers []string, prefix string, database moira.Database) error {
func handleRemoveUnusedTriggersWithTTL(logger moira.Logger, database moira.Database, ttl int64) error {
unusedTriggers, err := database.GetUnusedTriggerIDs()
if err != nil {
return fmt.Errorf("can't get unused trigger IDs; err: %w", err)
}

triggersToDelete := make([]string, 0)
nowInSec := time.Now().Unix()
for _, id := range unusedTriggers {
unusedTrigger, err := database.GetTrigger(id)
if err != nil {
logger.Error().
String(moira.LogFieldNameTriggerID, id).
Error(err).
Msg("cannot get trigger")

continue
}

if needDeleteTrigger(unusedTrigger.UpdatedAt, nowInSec, ttl) {
triggersToDelete = append(triggersToDelete, id)
}
}

return deleteTriggers(logger, triggersToDelete, database)
}

func needDeleteTrigger(timestamp *int64, nowInSec, ttl int64) bool {
if timestamp != nil {
return *timestamp+ttl < nowInSec
}

return true
}

func deleteTriggers(logger moira.Logger, triggers []string, database moira.Database) error {
logger.Info().
Int("triggers_to_delete", len(triggers)).
String("prefix", prefix).
String("delay", delay.String()).
Msg("Triggers that start with given prefix would be removed after delay")
Msg("Triggers would be removed after delay")

logger.Info().Msg("You can cancel execution by Ctrl+C")
time.Sleep(delay)

logger.Info().
String("prefix", prefix).
Msg("Removing triggers start with given prefix has started")
Msg("Removing triggers start with has started")

deletedTriggersCount := 0
for _, id := range triggers {
Expand All @@ -66,7 +100,6 @@ func deleteTriggers(logger moira.Logger, triggers []string, prefix string, datab
deletedTriggersCount++
}
logger.Info().
String("prefix", prefix).
Int("deleted_triggers_count", len(triggers)).
Interface("deleted_triggers", triggers).
Msg("Removing triggers start with given prefix has finished")
Expand Down
64 changes: 62 additions & 2 deletions cmd/cli/triggers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"time"

"github.com/golang/mock/gomock"
"github.com/moira-alert/moira"
logging "github.com/moira-alert/moira/logging/zerolog_adapter"
mocks "github.com/moira-alert/moira/mock/moira-alert"

Expand All @@ -24,7 +25,7 @@ func Test_deleteTriggers(t *testing.T) {
db.EXPECT().RemoveTrigger("trigger-2").Return(nil)

triggersToDelete := []string{"trigger-1", "trigger-2"}
err := deleteTriggers(logger, triggersToDelete, "trigger", db)
err := deleteTriggers(logger, triggersToDelete, db)
So(err, ShouldBeNil)
})

Expand All @@ -33,7 +34,7 @@ func Test_deleteTriggers(t *testing.T) {
db.EXPECT().RemoveTrigger("trigger-2").Return(errors.New("oops"))

triggersToDelete := []string{"trigger-1", "trigger-2"}
err := deleteTriggers(logger, triggersToDelete, "trigger", db)
err := deleteTriggers(logger, triggersToDelete, db)
So(err, ShouldNotBeNil)
So(err.Error(), ShouldResemble, "can't remove trigger with id trigger-2: oops")
})
Expand Down Expand Up @@ -101,3 +102,62 @@ func Test_handleRemoveUnusedTriggersStartWith(t *testing.T) {
So(err.Error(), ShouldResemble, "can't get unused trigger IDs; err: oops")
})
}

func Test_handleRemoveUnusedTriggersWithTTL(t *testing.T) {
logger, _ := logging.ConfigureLog("stdout", "debug", "test", true)
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
db := mocks.NewMockDatabase(mockCtrl)
delay = 1 * time.Millisecond
nowTime := time.Now()

Convey("Success delete triggers: updated at is set", t, func() {
updatedAt := nowTime.Add(-24 * time.Hour).Unix()
db.EXPECT().GetTrigger("trigger-1").Return(moira.Trigger{UpdatedAt: &updatedAt}, nil)
db.EXPECT().GetUnusedTriggerIDs().Return([]string{"trigger-1"}, nil)
db.EXPECT().RemoveTrigger("trigger-1").Return(nil)

ttl := int64(2 * time.Hour.Seconds())
err := handleRemoveUnusedTriggersWithTTL(logger, db, ttl)
So(err, ShouldBeNil)
})

Convey("Success delete triggers: updated_at is no set", t, func() {
db.EXPECT().GetTrigger("trigger-1").Return(moira.Trigger{}, nil)
db.EXPECT().GetUnusedTriggerIDs().Return([]string{"trigger-1"}, nil)
db.EXPECT().RemoveTrigger("trigger-1").Return(nil)

ttl := int64(2 * time.Hour.Seconds())
err := handleRemoveUnusedTriggersWithTTL(logger, db, ttl)
So(err, ShouldBeNil)
})

Convey("Error delete triggers: error while getting unused triggers, has error", t, func() {
db.EXPECT().GetUnusedTriggerIDs().Return([]string{"trigger-1"}, errors.New("error"))

ttl := int64(2 * time.Hour.Seconds())
err := handleRemoveUnusedTriggersWithTTL(logger, db, ttl)
So(err, ShouldNotBeNil)
So(err.Error(), ShouldResemble, "can't get unused trigger IDs; err: error")
})

Convey("Error delete triggers: error while get one trigger, has no error", t, func() {
db.EXPECT().GetUnusedTriggerIDs().Return([]string{"trigger-1"}, nil)
db.EXPECT().GetTrigger("trigger-1").Return(moira.Trigger{}, errors.New("error"))

ttl := int64(2 * time.Hour.Seconds())
err := handleRemoveUnusedTriggersWithTTL(logger, db, ttl)
So(err, ShouldBeNil)
})

Convey("Error delete triggers: error while delete one trigger, has error", t, func() {
db.EXPECT().GetUnusedTriggerIDs().Return([]string{"trigger-1"}, nil)
db.EXPECT().GetTrigger("trigger-1").Return(moira.Trigger{}, nil)
db.EXPECT().RemoveTrigger("trigger-1").Return(errors.New("error"))

ttl := int64(2 * time.Hour.Seconds())
err := handleRemoveUnusedTriggersWithTTL(logger, db, ttl)
So(err, ShouldNotBeNil)
So(err.Error(), ShouldResemble, "can't remove trigger with id trigger-1: error")
})
}

0 comments on commit fbd7e35

Please sign in to comment.