perf: improve scalability of session api (#9635)

This pull request improves the scalability of the session API by
enhancing middleware tracing and refining SQL query behavior for user
authentication methods.

# Which Problems Are Solved

- Eventstore subscriptions locked each other during they wrote the
events to the event channels of the subscribers in push.
- `ListUserAuthMethodTypesRequired` query used `Bitmap heap scan` to
join the tables needed.
- The auth and oidc package triggered projections often when data were
read.
- The session API triggered the user projection each time a user was
searched to write the user check command.

# How the Problems Are Solved

- the `sync.Mutex` was replaced with `sync.RWMutex` to allow parallel
read of the map
- The query was refactored to use index scans only
- if the data should already be up-to-date `shouldTriggerBulk` is set to
false
- as the user should already exist for some time the trigger was
removed.

# Additional Changes

- refactoring of `tracing#Span.End` calls

# Additional Context

- part of https://github.com/zitadel/zitadel/issues/9239

---------

Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
This commit is contained in:
Silvan
2025-03-28 13:36:05 +01:00
committed by GitHub
parent 79d1e7d434
commit 817670f1f7
13 changed files with 101 additions and 226 deletions

View File

@@ -3,6 +3,7 @@ package integration
import (
"context"
"fmt"
"sync"
"testing"
"time"
@@ -157,6 +158,7 @@ func (i *Instance) CreateHumanUser(ctx context.Context) *user_v2.AddHumanUserRes
},
})
logging.OnError(err).Panic("create human user")
i.TriggerUserByID(ctx, resp.GetUserId())
return resp
}
@@ -181,6 +183,7 @@ func (i *Instance) CreateHumanUserNoPhone(ctx context.Context) *user_v2.AddHuman
},
})
logging.OnError(err).Panic("create human user")
i.TriggerUserByID(ctx, resp.GetUserId())
return resp
}
@@ -212,9 +215,26 @@ func (i *Instance) CreateHumanUserWithTOTP(ctx context.Context, secret string) *
TotpSecret: gu.Ptr(secret),
})
logging.OnError(err).Panic("create human user")
i.TriggerUserByID(ctx, resp.GetUserId())
return resp
}
// TriggerUserByID makes sure the user projection gets triggered after creation.
func (i *Instance) TriggerUserByID(ctx context.Context, users ...string) {
var wg sync.WaitGroup
wg.Add(len(users))
for _, user := range users {
go func(user string) {
defer wg.Done()
_, err := i.Client.UserV2.GetUserByID(ctx, &user_v2.GetUserByIDRequest{
UserId: user,
})
logging.OnError(err).Warn("get user by ID for trigger failed")
}(user)
}
wg.Wait()
}
func (i *Instance) CreateOrganization(ctx context.Context, name, adminEmail string) *org.AddOrganizationResponse {
resp, err := i.Client.OrgV2.AddOrganization(ctx, &org.AddOrganizationRequest{
Name: name,
@@ -238,6 +258,13 @@ func (i *Instance) CreateOrganization(ctx context.Context, name, adminEmail stri
},
})
logging.OnError(err).Panic("create org")
users := make([]string, len(resp.GetCreatedAdmins()))
for i, admin := range resp.GetCreatedAdmins() {
users[i] = admin.GetUserId()
}
i.TriggerUserByID(ctx, users...)
return resp
}
@@ -302,6 +329,7 @@ func (i *Instance) CreateHumanUserVerified(ctx context.Context, org, email, phon
},
})
logging.OnError(err).Panic("create human user")
i.TriggerUserByID(ctx, resp.GetUserId())
return resp
}
@@ -313,6 +341,7 @@ func (i *Instance) CreateMachineUser(ctx context.Context) *mgmt.AddMachineUserRe
AccessTokenType: user_pb.AccessTokenType_ACCESS_TOKEN_TYPE_BEARER,
})
logging.OnError(err).Panic("create human user")
i.TriggerUserByID(ctx, resp.GetUserId())
return resp
}