mirror of
https://github.com/hrfee/jfa-go.git
synced 2026-01-18 16:47:42 +01:00
accounts: reduce initial load time further
When generating the cache and calling userSummary per user, previously the DB was queried for an invite with the ReferrerJellyfinID set to the user's ID. This was fast enough on my test system (~5000 users in ~1.5s), while testing cross-compilation, I found it ran extremely slow on an arm64 build (running through QEMU admittedly), doing ~5000 in ~18s. Instead, a map of IDs to invites/referrals is generated once and queried instead. Initial load now takes ~80ms on my system, and 0.95s through QEMU, and 0.68s on a rockpro64 SBC.
This commit is contained in:
27
api-users.go
27
api-users.go
@@ -902,9 +902,23 @@ func (app *appContext) AdminPasswordReset(gc *gin.Context) {
|
||||
respondBool(204, true, gc)
|
||||
}
|
||||
|
||||
// getActiveReferrals returns a map of jellyfin user IDs to their active referral "invite" code, if they have one.
|
||||
// It does not check if the user still exists, simply finding invites with the ReferrerJellyfinID field set.
|
||||
func (app *appContext) getActiveReferrals() map[string]string {
|
||||
out := map[string]string{}
|
||||
for _, inv := range app.storage.GetInvites() {
|
||||
if inv.ReferrerJellyfinID == "" {
|
||||
continue
|
||||
}
|
||||
out[inv.ReferrerJellyfinID] = inv.Code
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// userSummary generates a respUser for to be displayed to the user, or sorted/filtered.
|
||||
// also, consider it a source of which data fields/struct modifications need to trigger a cache invalidation.
|
||||
func (app *appContext) userSummary(jfUser mediabrowser.User) respUser {
|
||||
// referralCache can be passed to avoid querying the db each time this is called. It can be generated with app.getActiveReferrals().
|
||||
func (app *appContext) userSummary(jfUser mediabrowser.User, referralCache *map[string]string) respUser {
|
||||
adminOnly := app.config.Section("ui").Key("admin_only").MustBool(true)
|
||||
allowAll := app.config.Section("ui").Key("allow_all").MustBool(false)
|
||||
referralsEnabled := app.config.Section("user_page").Key("referrals").MustBool(false)
|
||||
@@ -944,10 +958,17 @@ func (app *appContext) userSummary(jfUser mediabrowser.User) respUser {
|
||||
}
|
||||
// FIXME: Send referral data
|
||||
referrerInv := Invite{}
|
||||
// FIXME: This is veeery slow when running an arm64 binary through qemu
|
||||
if referralsEnabled {
|
||||
// 1. Directly attached invite.
|
||||
err := app.storage.db.FindOne(&referrerInv, badgerhold.Where("ReferrerJellyfinID").Eq(jfUser.ID))
|
||||
if err == nil {
|
||||
found := false
|
||||
if referralCache != nil {
|
||||
_, found = (*referralCache)[jfUser.ID]
|
||||
} else {
|
||||
err := app.storage.db.FindOne(&referrerInv, badgerhold.Where("IsReferral").Eq(true).And("ReferrerJellyfinID").Eq(jfUser.ID))
|
||||
found = err == nil
|
||||
}
|
||||
if found {
|
||||
user.ReferralsEnabled = true
|
||||
// 2. Referrals via profile template. Shallow check, doesn't look for the thing in the database.
|
||||
} else if email, ok := app.storage.GetEmailsKey(jfUser.ID); ok && email.ReferralTemplateKey != "" {
|
||||
|
||||
@@ -328,6 +328,9 @@ const (
|
||||
|
||||
// webhooks.go
|
||||
WebhookRequest = "Webhook request send to \"%s\" (%d): %v"
|
||||
|
||||
// usercache.go
|
||||
CacheRefreshCompleted = "Usercache refreshed, %d in %.2fs (%f.2u/sec)"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
lm "github.com/hrfee/jfa-go/logmessages"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -85,10 +87,12 @@ func (c *UserCache) MaybeSync(app *appContext) error {
|
||||
status <- err
|
||||
return
|
||||
}
|
||||
startTime := time.Now()
|
||||
cache := make([]respUser, len(users))
|
||||
labels := map[string]bool{}
|
||||
referralCache := app.getActiveReferrals()
|
||||
for i, jfUser := range users {
|
||||
cache[i] = app.userSummary(jfUser)
|
||||
cache[i] = app.userSummary(jfUser, &referralCache)
|
||||
if cache[i].Label != "" {
|
||||
labels[cache[i].Label] = true
|
||||
}
|
||||
@@ -101,6 +105,9 @@ func (c *UserCache) MaybeSync(app *appContext) error {
|
||||
for label, _ := range labels {
|
||||
labelSlice = append(labelSlice, label)
|
||||
}
|
||||
elapsed := time.Since(startTime).Seconds()
|
||||
usersPerSec := float64(len(users)) / elapsed
|
||||
app.debug.Printf(lm.CacheRefreshCompleted, len(users), elapsed, usersPerSec)
|
||||
c.Cache = cache
|
||||
c.Ref = ref
|
||||
c.Sorted = false
|
||||
|
||||
2
users.go
2
users.go
@@ -141,7 +141,7 @@ func (app *appContext) NewUserPostVerification(p NewUserParams) (out NewUserData
|
||||
|
||||
webhookURIs := app.config.Section("webhooks").Key("created").StringsWithShadows("|")
|
||||
if len(webhookURIs) != 0 {
|
||||
summary := app.userSummary(out.User)
|
||||
summary := app.userSummary(out.User, nil)
|
||||
for _, uri := range webhookURIs {
|
||||
pendingTasks.Add(1)
|
||||
go func() {
|
||||
|
||||
Reference in New Issue
Block a user