Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/remove unused triggers #1033

Merged
merged 4 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
50 changes: 42 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,56 @@ 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)
continue
}
}

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 +101,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")
})
}
Loading