···437437438438type RateLimitChangeRequest struct {
439439 Hostname string `json:"host"`
440440- RepoLimit int64 `json:"repo_limit,omitempty"`
440440+ RepoLimit *int64 `json:"repo_limit"`
441441}
442442443443func (s *Service) handleAdminChangeHostRateLimits(c echo.Context) error {
···453453 return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("invalid hostname: %s", err))
454454 }
455455456456+ // catch empty/nil body
457457+ if body.RepoLimit == nil {
458458+ return echo.NewHTTPError(http.StatusBadRequest, "missing repo_limit parameter")
459459+ }
460460+456461 host, err := s.relay.GetHost(ctx, hostname)
457462 if err != nil {
458463 // TODO: technically, there could be a database error here or something
459464 return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("unknown hostname: %s", err))
460465 }
461466462462- if err := s.relay.UpdateHostAccountLimit(ctx, host.ID, body.RepoLimit); err != nil {
467467+ if err := s.relay.UpdateHostAccountLimit(ctx, host.ID, *body.RepoLimit); err != nil {
463468 return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to update limits: %s", err))
464469 }
465470
+24-3
cmd/relay/relay/host.go
···7878 return err
7979 }
80808181- // TODO: manage accounts marked as "host-throttled" when host-level account limits change (all in a transaction)
8282- // If limit increased: potentially mark some "host-throttled" accounts as "active" (ordered by UID ascending)
8383- // If limit decreased: potentially mark some "active" accounts as "host-throttled" (ordered by UID descending?)
8181+ delta := accountLimit - host.AccountLimit
8282+ r.Logger.Info("updating host account limit", "host", host.Hostname, "accountLimit", accountLimit, "previousAccountLimit", host.AccountLimit)
8383+8484 if err := r.db.Model(models.Host{}).Where("id = ?", hostID).Update("account_limit", accountLimit).Error; err != nil {
8585 return err
8686 }
8787+8888+ // manage accounts marked as "host-throttled" when host-level account limits change. Note that this isn't in a transaction: there is a small chance of race-conditions.
8989+ if delta > 0 {
9090+ // if limit increased: potentially mark some "host-throttled" accounts as "active" (ordered by UID ascending)
9191+ // fetch accounts and update individually. this ensures that account cache is cleared for each (as well as any future code around account status changes)
9292+ var accounts []models.Account
9393+ if err := r.db.Model(models.Account{}).Where("status = ? AND upstream_status = ? AND host_id = ?", models.AccountStatusHostThrottled, models.AccountStatusActive, host.ID).Order("uid ASC").Limit(int(delta)).Find(&accounts).Error; err != nil {
9494+ return err
9595+ }
9696+ r.Logger.Info("marking host-throttled accounts as active", "count", len(accounts), "delta", delta, "accountLimit", accountLimit, "host", host.Hostname)
9797+ for _, acc := range accounts {
9898+ // defensive double-check
9999+ if acc.Status != models.AccountStatusHostThrottled || acc.HostID != host.ID {
100100+ continue
101101+ }
102102+ if err := r.UpdateAccountLocalStatus(ctx, syntax.DID(acc.DID), models.AccountStatusActive, true); err != nil {
103103+ return err
104104+ }
105105+ }
106106+ }
107107+ // TODO: If limit decreased: potentially mark some "active" accounts as "host-throttled" (ordered by UID descending?)
8710888109 if r.Slurper.CheckIfSubscribed(host.Hostname) {
89110 return r.Slurper.UpdateLimiters(host.Hostname, accountLimit, host.Trusted)