chore: move dormancy to enterprise package (#9468)

This commit is contained in:
Marcin Tojek
2023-08-31 17:59:53 +02:00
committed by GitHub
parent 7c4ce62a58
commit 11d4b6f758
5 changed files with 10 additions and 5 deletions

View File

@ -1,70 +0,0 @@
package dormancy
import (
"context"
"database/sql"
"time"
"golang.org/x/xerrors"
"cdr.dev/slog"
"github.com/coder/coder/v2/coderd/database"
)
const (
// Time interval between consecutive job runs
jobInterval = 15 * time.Minute
// User accounts inactive for `accountDormancyPeriod` will be marked as dormant
accountDormancyPeriod = 90 * 24 * time.Hour
)
// CheckInactiveUsers function updates status of inactive users from active to dormant
// using default parameters.
func CheckInactiveUsers(ctx context.Context, logger slog.Logger, db database.Store) func() {
return CheckInactiveUsersWithOptions(ctx, logger, db, jobInterval, accountDormancyPeriod)
}
// CheckInactiveUsersWithOptions function updates status of inactive users from active to dormant
// using provided parameters.
func CheckInactiveUsersWithOptions(ctx context.Context, logger slog.Logger, db database.Store, checkInterval, dormancyPeriod time.Duration) func() {
logger = logger.Named("dormancy")
ctx, cancelFunc := context.WithCancel(ctx)
done := make(chan struct{})
ticker := time.NewTicker(checkInterval)
go func() {
defer close(done)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
}
startTime := time.Now()
lastSeenAfter := database.Now().Add(-dormancyPeriod)
logger.Debug(ctx, "check inactive user accounts", slog.F("dormancy_period", dormancyPeriod), slog.F("last_seen_after", lastSeenAfter))
updatedUsers, err := db.UpdateInactiveUsersToDormant(ctx, database.UpdateInactiveUsersToDormantParams{
LastSeenAfter: lastSeenAfter,
UpdatedAt: database.Now(),
})
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
logger.Error(ctx, "can't mark inactive users as dormant", slog.Error(err))
continue
}
for _, u := range updatedUsers {
logger.Info(ctx, "account has been marked as dormant", slog.F("email", u.Email), slog.F("last_seen_at", u.LastSeenAt))
}
logger.Debug(ctx, "checking user accounts is done", slog.F("num_dormant_accounts", len(updatedUsers)), slog.F("execution_time", time.Since(startTime)))
}
}()
return func() {
cancelFunc()
<-done
}
}

View File

@ -1,110 +0,0 @@
package dormancy_test
import (
"context"
"testing"
"time"
"github.com/google/uuid"
"github.com/moby/moby/pkg/namesgenerator"
"github.com/stretchr/testify/require"
"cdr.dev/slog/sloggers/slogtest"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbfake"
"github.com/coder/coder/v2/coderd/dormancy"
"github.com/coder/coder/v2/testutil"
)
func TestCheckInactiveUsers(t *testing.T) {
t.Parallel()
// Predefine job settings
interval := time.Millisecond
dormancyPeriod := 90 * 24 * time.Hour
// Add some dormant accounts
logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
db := dbfake.New()
ctx, cancelFunc := context.WithCancel(context.Background())
t.Cleanup(cancelFunc)
inactiveUser1 := setupUser(ctx, t, db, "dormant-user-1@coder.com", database.UserStatusActive, time.Now().Add(-dormancyPeriod).Add(-time.Minute))
inactiveUser2 := setupUser(ctx, t, db, "dormant-user-2@coder.com", database.UserStatusActive, time.Now().Add(-dormancyPeriod).Add(-time.Hour))
inactiveUser3 := setupUser(ctx, t, db, "dormant-user-3@coder.com", database.UserStatusActive, time.Now().Add(-dormancyPeriod).Add(-6*time.Hour))
activeUser1 := setupUser(ctx, t, db, "active-user-1@coder.com", database.UserStatusActive, time.Now().Add(-dormancyPeriod).Add(time.Minute))
activeUser2 := setupUser(ctx, t, db, "active-user-2@coder.com", database.UserStatusActive, time.Now().Add(-dormancyPeriod).Add(time.Hour))
activeUser3 := setupUser(ctx, t, db, "active-user-3@coder.com", database.UserStatusActive, time.Now().Add(-dormancyPeriod).Add(6*time.Hour))
suspendedUser1 := setupUser(ctx, t, db, "suspended-user-1@coder.com", database.UserStatusSuspended, time.Now().Add(-dormancyPeriod).Add(-time.Minute))
suspendedUser2 := setupUser(ctx, t, db, "suspended-user-2@coder.com", database.UserStatusSuspended, time.Now().Add(-dormancyPeriod).Add(-time.Hour))
suspendedUser3 := setupUser(ctx, t, db, "suspended-user-3@coder.com", database.UserStatusSuspended, time.Now().Add(-dormancyPeriod).Add(-6*time.Hour))
// Run the periodic job
closeFunc := dormancy.CheckInactiveUsersWithOptions(ctx, logger, db, interval, dormancyPeriod)
t.Cleanup(closeFunc)
var rows []database.GetUsersRow
var err error
require.Eventually(t, func() bool {
rows, err = db.GetUsers(ctx, database.GetUsersParams{})
if err != nil {
return false
}
var dormant, suspended int
for _, row := range rows {
if row.Status == database.UserStatusDormant {
dormant++
} else if row.Status == database.UserStatusSuspended {
suspended++
}
}
// 6 users in total, 3 dormant, 3 suspended
return len(rows) == 9 && dormant == 3 && suspended == 3
}, testutil.WaitShort, testutil.IntervalMedium)
allUsers := ignoreUpdatedAt(database.ConvertUserRows(rows))
// Verify user status
expectedUsers := []database.User{
asDormant(inactiveUser1),
asDormant(inactiveUser2),
asDormant(inactiveUser3),
activeUser1,
activeUser2,
activeUser3,
suspendedUser1,
suspendedUser2,
suspendedUser3,
}
require.ElementsMatch(t, allUsers, expectedUsers)
}
func setupUser(ctx context.Context, t *testing.T, db database.Store, email string, status database.UserStatus, lastSeenAt time.Time) database.User {
t.Helper()
user, err := db.InsertUser(ctx, database.InsertUserParams{ID: uuid.New(), LoginType: database.LoginTypePassword, Username: namesgenerator.GetRandomName(8), Email: email})
require.NoError(t, err)
// At the beginning of the test all users are marked as active
user, err = db.UpdateUserStatus(ctx, database.UpdateUserStatusParams{ID: user.ID, Status: status})
require.NoError(t, err)
user, err = db.UpdateUserLastSeenAt(ctx, database.UpdateUserLastSeenAtParams{ID: user.ID, LastSeenAt: lastSeenAt})
require.NoError(t, err)
return user
}
func asDormant(user database.User) database.User {
user.Status = database.UserStatusDormant
return user
}
func ignoreUpdatedAt(rows []database.User) []database.User {
for i := range rows {
rows[i].UpdatedAt = time.Time{}
}
return rows
}