root: move database calls from ready() to dedicated startup signal (#9081)

* root: move database calls from ready() to dedicated startup signal

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* optimise gunicorn startup to only do DB code in one worker

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* always use 2 workers in compose

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* send startup signals for test runner

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* remove k8s import that isn't really needed

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* ci: bump nested actions

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix @reconcile_app not triggering reconcile due to changed functions

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* connect startup with uid

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* adjust some log levels

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* remove internal healthcheck

we didn't really use it to do anything, and we shouldn't have to since the live/ready probes are handled by django anyways and so the container runtime will restart the server if needed

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add setproctitle for gunicorn and celery process titles

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* configure structlog early to use it

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* Revert "configure structlog early to use it"

This reverts commit 16778fdbbca0f5c474d376c2f85c6f8032c06044.

* Revert "adjust some log levels"

This reverts commit a129f7ab6aecf27f1206aea1ad8384ce897b74ad.

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

# Conflicts:
#	authentik/root/settings.py

* optimize startup to not spawn a bunch of one-off processes

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* idk why this shows up

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L
2024-04-02 14:19:32 +02:00
committed by GitHub
parent 4d8ee983ef
commit 7ea721c487
21 changed files with 290 additions and 82 deletions

View File

@ -16,18 +16,18 @@ runs:
sudo apt-get update
sudo apt-get install --no-install-recommends -y libpq-dev openssl libxmlsec1-dev pkg-config gettext
- name: Setup python and restore poetry
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version-file: "pyproject.toml"
cache: "poetry"
- name: Setup node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version-file: web/package.json
cache: "npm"
cache-dependency-path: web/package-lock.json
- name: Setup go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
- name: Setup dependencies

View File

@ -8,6 +8,8 @@ from django.apps import AppConfig
from django.db import DatabaseError, InternalError, ProgrammingError
from structlog.stdlib import BoundLogger, get_logger
from authentik.root.signals import startup
class ManagedAppConfig(AppConfig):
"""Basic reconciliation logic for apps"""
@ -23,9 +25,12 @@ class ManagedAppConfig(AppConfig):
def ready(self) -> None:
self.import_related()
startup.connect(self._on_startup_callback, dispatch_uid=self.label)
return super().ready()
def _on_startup_callback(self, sender, **_):
self._reconcile_global()
self._reconcile_tenant()
return super().ready()
def import_related(self):
"""Automatically import related modules which rely on just being imported

View File

@ -39,7 +39,7 @@ def reconcile_app(app_name: str):
def wrapper(*args, **kwargs):
config = apps.get_app_config(app_name)
if isinstance(config, ManagedAppConfig):
config.ready()
config._on_startup_callback(None)
return func(*args, **kwargs)
return wrapper

View File

@ -1,10 +1,34 @@
"""custom runserver command"""
from typing import TextIO
from daphne.management.commands.runserver import Command as RunServer
from daphne.server import Server
from authentik.root.signals import post_startup, pre_startup, startup
class SignalServer(Server):
"""Server which signals back to authentik when it finished starting up"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def ready_callable():
pre_startup.send(sender=self)
startup.send(sender=self)
post_startup.send(sender=self)
self.ready_callable = ready_callable
class Command(RunServer):
"""custom runserver command, which doesn't show the misleading django startup message"""
def on_bind(self, server_port):
pass
server_cls = SignalServer
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Redirect standard stdout banner from Daphne into the void
# as there are a couple more steps that happen before startup is fully done
self.stdout = TextIO()

View File

@ -3,12 +3,14 @@
import os
from importlib import import_module
from pathlib import Path
from tempfile import gettempdir
from django.conf import settings
from kubernetes.config.incluster_config import SERVICE_HOST_ENV_NAME
from authentik.lib.config import CONFIG
SERVICE_HOST_ENV_NAME = "KUBERNETES_SERVICE_HOST"
def all_subclasses(cls, sort=True):
"""Recursively return all subclassess of cls"""
@ -55,7 +57,7 @@ def get_env() -> str:
return "dev"
if SERVICE_HOST_ENV_NAME in os.environ:
return "kubernetes"
if Path("/tmp/authentik-mode").exists(): # nosec
if (Path(gettempdir()) / "authentik-mode").exists():
return "compose"
if "AK_APPLIANCE" in os.environ:
return os.environ["AK_APPLIANCE"]

View File

@ -45,14 +45,14 @@ class AuthentikOutpostConfig(ManagedAppConfig):
outpost.managed = MANAGED_OUTPOST
outpost.save()
return
outpost, updated = Outpost.objects.update_or_create(
outpost, created = Outpost.objects.update_or_create(
defaults={
"type": OutpostType.PROXY,
"name": MANAGED_OUTPOST_NAME,
},
managed=MANAGED_OUTPOST,
)
if updated:
if created:
if KubernetesServiceConnection.objects.exists():
outpost.service_connection = KubernetesServiceConnection.objects.first()
elif DockerServiceConnection.objects.exists():

View File

@ -60,7 +60,18 @@ class RouteNotFoundMiddleware:
raise exc
application = SentryAsgiMiddleware(
class AuthentikAsgi(SentryAsgiMiddleware):
"""Root ASGI App wrapper"""
def call_startup(self):
from authentik.root.signals import post_startup, pre_startup, startup
pre_startup.send(sender=self)
startup.send(sender=self)
post_startup.send(sender=self)
application = AuthentikAsgi(
ProtocolTypeRouter(
{
"http": get_asgi_application(),

26
authentik/root/signals.py Normal file
View File

@ -0,0 +1,26 @@
from datetime import timedelta
from django.core.signals import Signal
from django.dispatch import receiver
from django.utils.timezone import now
from structlog.stdlib import get_logger
# Signal dispatched before actual startup trigger
pre_startup = Signal()
# Signal dispatched which should trigger all startup logic
startup = Signal()
# Signal dispatched after the startup logic
post_startup = Signal()
LOGGER = get_logger()
@receiver(pre_startup)
def pre_startup_log(sender, **_):
sender._start_time = now()
@receiver(post_startup)
def post_startup_log(sender, **_):
took: timedelta = now() - sender._start_time
LOGGER.info("authentik Core Worker finished starting", took_s=took.total_seconds())

View File

@ -9,6 +9,7 @@ from django.test.runner import DiscoverRunner
from authentik.lib.config import CONFIG
from authentik.lib.sentry import sentry_init
from authentik.root.signals import post_startup, pre_startup, startup
from tests.e2e.utils import get_docker_tag
# globally set maxDiff to none to show full assert error
@ -46,6 +47,10 @@ class PytestTestRunner(DiscoverRunner): # pragma: no cover
CONFIG.set("error_reporting.send_pii", True)
sentry_init()
pre_startup.send(sender=self, mode="test")
startup.send(sender=self, mode="test")
post_startup.send(sender=self, mode="test")
@classmethod
def add_arguments(cls, parser: ArgumentParser):
"""Add more pytest-specific arguments"""

View File

@ -96,18 +96,15 @@ func (g *GoUnicorn) healthcheck() {
g.log.Debug("starting healthcheck")
// Default healthcheck is every 1 second on startup
// once we've been healthy once, increase to 30 seconds
for range time.Tick(time.Second) {
for range time.NewTicker(time.Second).C {
if g.Healthcheck() {
g.alive = true
g.log.Info("backend is alive, backing off with healthchecks")
g.log.Debug("backend is alive, backing off with healthchecks")
g.HealthyCallback()
break
}
g.log.Debug("backend not alive yet")
}
for range time.Tick(30 * time.Second) {
g.Healthcheck()
}
}
func (g *GoUnicorn) Reload() {

View File

@ -32,9 +32,6 @@ func (ws *WebServer) configureProxy() {
}
rp.ErrorHandler = ws.proxyErrorHandler
rp.ModifyResponse = ws.proxyModifyResponse
ws.m.Path("/-/health/live/").HandlerFunc(sentry.SentryNoSample(func(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(204)
}))
ws.m.PathPrefix("/").HandlerFunc(sentry.SentryNoSample(func(rw http.ResponseWriter, r *http.Request) {
if !ws.g.IsRunning() {
ws.proxyErrorHandler(rw, r, errors.New("authentik starting"))

View File

@ -7,7 +7,6 @@ function log {
function wait_for_db {
python -m lifecycle.wait_for_db
python -m lifecycle.migrate
log "Bootstrap completed"
}
@ -65,7 +64,6 @@ if [[ "${AUTHENTIK_REMOTE_DEBUG}" == "true" ]]; then
fi
if [[ "$1" == "server" ]]; then
wait_for_db
set_mode "server"
# If we have bootstrap credentials set, run bootstrap tasks outside of main server
# sync, so that we can sure the first start actually has working bootstrap
@ -75,7 +73,6 @@ if [[ "$1" == "server" ]]; then
fi
run_authentik
elif [[ "$1" == "worker" ]]; then
wait_for_db
set_mode "worker"
check_if_root "python -m manage worker"
elif [[ "$1" == "worker-status" ]]; then

View File

@ -2,13 +2,11 @@
import os
from hashlib import sha512
from multiprocessing import cpu_count
from os import makedirs
from pathlib import Path
from tempfile import gettempdir
from typing import TYPE_CHECKING
from kubernetes.config.incluster_config import SERVICE_HOST_ENV_NAME
from prometheus_client.values import MultiProcessValue
from authentik import get_full_version
@ -17,11 +15,18 @@ from authentik.lib.logging import get_logger_config
from authentik.lib.utils.http import get_http_session
from authentik.lib.utils.reflection import get_env
from authentik.root.install_id import get_install_id_raw
from lifecycle.migrate import run_migrations
from lifecycle.wait_for_db import wait_for_db
from lifecycle.worker import DjangoUvicornWorker
if TYPE_CHECKING:
from gunicorn.app.wsgiapp import WSGIApplication
from gunicorn.arbiter import Arbiter
from authentik.root.asgi import AuthentikAsgi
wait_for_db()
_tmp = Path(gettempdir())
worker_class = "lifecycle.worker.DjangoUvicornWorker"
worker_tmp_dir = str(_tmp.joinpath("authentik_worker_tmp"))
@ -35,17 +40,14 @@ bind = f"unix://{str(_tmp.joinpath('authentik-core.sock'))}"
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings")
os.environ.setdefault("PROMETHEUS_MULTIPROC_DIR", prometheus_tmp_dir)
preload = True
max_requests = 1000
max_requests_jitter = 50
logconfig_dict = get_logger_config()
# if we're running in kubernetes, use fixed workers because we can scale with more pods
# otherwise (assume docker-compose), use as much as we can
if SERVICE_HOST_ENV_NAME in os.environ:
default_workers = 2
else:
default_workers = max(cpu_count() * 0.25, 1) + 1 # Minimum of 2 workers
default_workers = 2
workers = CONFIG.get_int("web.workers", default_workers)
threads = CONFIG.get_int("web.threads", 4)
@ -100,6 +102,18 @@ def pre_fork(server: "Arbiter", worker: DjangoUvicornWorker):
worker._worker_id = _next_worker_id(server)
def post_worker_init(worker: DjangoUvicornWorker):
"""Notify ASGI app that its started up"""
# Only trigger startup DB logic on first worker
# Startup code that imports code or is otherwise needed in every worker
# does not use this signal, so we can skip this safely
if worker._worker_id != 1:
return
app: "WSGIApplication" = worker.app
root_app: "AuthentikAsgi" = app.callable
root_app.call_startup()
if not CONFIG.get_bool("disable_startup_analytics", False):
env = get_env()
should_send = env not in ["dev", "ci"]
@ -129,3 +143,5 @@ if CONFIG.get_bool("remote_debug"):
import debugpy
debugpy.listen(("0.0.0.0", 6800)) # nosec
run_migrations()

View File

@ -68,7 +68,7 @@ def release_lock(cursor: Cursor):
cursor.execute("SELECT pg_advisory_unlock(%s)", (ADV_LOCK_UID,))
if __name__ == "__main__":
def run_migrations():
conn = connect(
dbname=CONFIG.get("postgresql.name"),
user=CONFIG.get("postgresql.user"),
@ -117,3 +117,7 @@ if __name__ == "__main__":
)
finally:
release_lock(curr)
if __name__ == "__main__":
run_migrations()

View File

@ -11,17 +11,9 @@ from redis.exceptions import RedisError
from authentik.lib.config import CONFIG
CONFIG.log("info", "Starting authentik bootstrap")
# Sanity check, ensure SECRET_KEY is set before we even check for database connectivity
if CONFIG.get("secret_key") is None or len(CONFIG.get("secret_key")) == 0:
CONFIG.log("info", "----------------------------------------------------------------------")
CONFIG.log("info", "Secret key missing, check https://goauthentik.io/docs/installation/.")
CONFIG.log("info", "----------------------------------------------------------------------")
sysexit(1)
while True:
def check_postgres():
while True:
try:
conn = connect(
dbname=CONFIG.get("postgresql.name"),
@ -39,17 +31,19 @@ while True:
except OperationalError as exc:
sleep(1)
CONFIG.log("info", f"PostgreSQL connection failed, retrying... ({exc})")
CONFIG.log("info", "PostgreSQL connection successful")
CONFIG.log("info", "PostgreSQL connection successful")
REDIS_PROTOCOL_PREFIX = "redis://"
if CONFIG.get_bool("redis.tls", False):
def check_redis():
REDIS_PROTOCOL_PREFIX = "redis://"
if CONFIG.get_bool("redis.tls", False):
REDIS_PROTOCOL_PREFIX = "rediss://"
REDIS_URL = (
REDIS_URL = (
f"{REDIS_PROTOCOL_PREFIX}:"
f"{quote_plus(CONFIG.get('redis.password'))}@{quote_plus(CONFIG.get('redis.host'))}:"
f"{CONFIG.get_int('redis.port')}/{CONFIG.get('redis.db')}"
)
while True:
)
while True:
try:
redis = Redis.from_url(REDIS_URL)
redis.ping()
@ -57,6 +51,21 @@ while True:
except RedisError as exc:
sleep(1)
CONFIG.log("info", f"Redis Connection failed, retrying... ({exc})", redis_url=REDIS_URL)
CONFIG.log("info", "Redis Connection successful")
CONFIG.log("info", "Redis Connection successful")
CONFIG.log("info", "Finished authentik bootstrap")
def wait_for_db():
CONFIG.log("info", "Starting authentik bootstrap")
# Sanity check, ensure SECRET_KEY is set before we even check for database connectivity
if CONFIG.get("secret_key") is None or len(CONFIG.get("secret_key")) == 0:
CONFIG.log("info", "----------------------------------------------------------------------")
CONFIG.log("info", "Secret key missing, check https://goauthentik.io/docs/installation/.")
CONFIG.log("info", "----------------------------------------------------------------------")
sysexit(1)
check_postgres()
check_redis()
CONFIG.log("info", "Finished authentik bootstrap")
if __name__ == "__main__":
wait_for_db()

View File

@ -12,3 +12,5 @@ class DjangoUvicornWorker(UvicornWorker):
"lifespan": "off",
"ws": "wsproto",
}
_worker_id: int

View File

@ -5,6 +5,10 @@ import sys
import warnings
from defusedxml import defuse_stdlib
from django.utils.autoreload import DJANGO_AUTORELOAD_ENV
from lifecycle.migrate import run_migrations
from lifecycle.wait_for_db import wait_for_db
warnings.filterwarnings("ignore", "SelectableGroups dict interface")
warnings.filterwarnings(
@ -20,6 +24,17 @@ defuse_stdlib()
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings")
wait_for_db()
if (
len(sys.argv) > 1
# Explicitly only run migrate for server and worker
# `bootstrap_tasks` is a special case as that command might be triggered by the `ak`
# script to pre-run certain tasks for an automated install
and sys.argv[1] in ["dev_server", "worker", "bootstrap_tasks"]
# and don't run if this is the child process of a dev_server
and os.environ.get(DJANGO_AUTORELOAD_ENV, None) is None
):
run_migrations()
try:
from django.core.management import execute_from_command_line
except ImportError as exc:

102
poetry.lock generated
View File

@ -3637,6 +3637,106 @@ idna = ["idna"]
mypy = ["idna", "mypy", "types-pyopenssl"]
tests = ["coverage[toml] (>=5.0.2)", "pytest"]
[[package]]
name = "setproctitle"
version = "1.3.3"
description = "A Python module to customize the process title"
optional = false
python-versions = ">=3.7"
files = [
{file = "setproctitle-1.3.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:897a73208da48db41e687225f355ce993167079eda1260ba5e13c4e53be7f754"},
{file = "setproctitle-1.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8c331e91a14ba4076f88c29c777ad6b58639530ed5b24b5564b5ed2fd7a95452"},
{file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbbd6c7de0771c84b4aa30e70b409565eb1fc13627a723ca6be774ed6b9d9fa3"},
{file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c05ac48ef16ee013b8a326c63e4610e2430dbec037ec5c5b58fcced550382b74"},
{file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1342f4fdb37f89d3e3c1c0a59d6ddbedbde838fff5c51178a7982993d238fe4f"},
{file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc74e84fdfa96821580fb5e9c0b0777c1c4779434ce16d3d62a9c4d8c710df39"},
{file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9617b676b95adb412bb69645d5b077d664b6882bb0d37bfdafbbb1b999568d85"},
{file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6a249415f5bb88b5e9e8c4db47f609e0bf0e20a75e8d744ea787f3092ba1f2d0"},
{file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:38da436a0aaace9add67b999eb6abe4b84397edf4a78ec28f264e5b4c9d53cd5"},
{file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:da0d57edd4c95bf221b2ebbaa061e65b1788f1544977288bdf95831b6e44e44d"},
{file = "setproctitle-1.3.3-cp310-cp310-win32.whl", hash = "sha256:a1fcac43918b836ace25f69b1dca8c9395253ad8152b625064415b1d2f9be4fb"},
{file = "setproctitle-1.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:200620c3b15388d7f3f97e0ae26599c0c378fdf07ae9ac5a13616e933cbd2086"},
{file = "setproctitle-1.3.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:334f7ed39895d692f753a443102dd5fed180c571eb6a48b2a5b7f5b3564908c8"},
{file = "setproctitle-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:950f6476d56ff7817a8fed4ab207727fc5260af83481b2a4b125f32844df513a"},
{file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:195c961f54a09eb2acabbfc90c413955cf16c6e2f8caa2adbf2237d1019c7dd8"},
{file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f05e66746bf9fe6a3397ec246fe481096664a9c97eb3fea6004735a4daf867fd"},
{file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5901a31012a40ec913265b64e48c2a4059278d9f4e6be628441482dd13fb8b5"},
{file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64286f8a995f2cd934082b398fc63fca7d5ffe31f0e27e75b3ca6b4efda4e353"},
{file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:184239903bbc6b813b1a8fc86394dc6ca7d20e2ebe6f69f716bec301e4b0199d"},
{file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:664698ae0013f986118064b6676d7dcd28fefd0d7d5a5ae9497cbc10cba48fa5"},
{file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e5119a211c2e98ff18b9908ba62a3bd0e3fabb02a29277a7232a6fb4b2560aa0"},
{file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:417de6b2e214e837827067048f61841f5d7fc27926f2e43954567094051aff18"},
{file = "setproctitle-1.3.3-cp311-cp311-win32.whl", hash = "sha256:6a143b31d758296dc2f440175f6c8e0b5301ced3b0f477b84ca43cdcf7f2f476"},
{file = "setproctitle-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:a680d62c399fa4b44899094027ec9a1bdaf6f31c650e44183b50d4c4d0ccc085"},
{file = "setproctitle-1.3.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d4460795a8a7a391e3567b902ec5bdf6c60a47d791c3b1d27080fc203d11c9dc"},
{file = "setproctitle-1.3.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bdfd7254745bb737ca1384dee57e6523651892f0ea2a7344490e9caefcc35e64"},
{file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:477d3da48e216d7fc04bddab67b0dcde633e19f484a146fd2a34bb0e9dbb4a1e"},
{file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ab2900d111e93aff5df9fddc64cf51ca4ef2c9f98702ce26524f1acc5a786ae7"},
{file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:088b9efc62d5aa5d6edf6cba1cf0c81f4488b5ce1c0342a8b67ae39d64001120"},
{file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6d50252377db62d6a0bb82cc898089916457f2db2041e1d03ce7fadd4a07381"},
{file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:87e668f9561fd3a457ba189edfc9e37709261287b52293c115ae3487a24b92f6"},
{file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:287490eb90e7a0ddd22e74c89a92cc922389daa95babc833c08cf80c84c4df0a"},
{file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:4fe1c49486109f72d502f8be569972e27f385fe632bd8895f4730df3c87d5ac8"},
{file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4a6ba2494a6449b1f477bd3e67935c2b7b0274f2f6dcd0f7c6aceae10c6c6ba3"},
{file = "setproctitle-1.3.3-cp312-cp312-win32.whl", hash = "sha256:2df2b67e4b1d7498632e18c56722851ba4db5d6a0c91aaf0fd395111e51cdcf4"},
{file = "setproctitle-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:f38d48abc121263f3b62943f84cbaede05749047e428409c2c199664feb6abc7"},
{file = "setproctitle-1.3.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:816330675e3504ae4d9a2185c46b573105d2310c20b19ea2b4596a9460a4f674"},
{file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68f960bc22d8d8e4ac886d1e2e21ccbd283adcf3c43136161c1ba0fa509088e0"},
{file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e6e7adff74796ef12753ff399491b8827f84f6c77659d71bd0b35870a17d8f"},
{file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53bc0d2358507596c22b02db079618451f3bd720755d88e3cccd840bafb4c41c"},
{file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad6d20f9541f5f6ac63df553b6d7a04f313947f550eab6a61aa758b45f0d5657"},
{file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c1c84beab776b0becaa368254801e57692ed749d935469ac10e2b9b825dbdd8e"},
{file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:507e8dc2891021350eaea40a44ddd887c9f006e6b599af8d64a505c0f718f170"},
{file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b1067647ac7aba0b44b591936118a22847bda3c507b0a42d74272256a7a798e9"},
{file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2e71f6365744bf53714e8bd2522b3c9c1d83f52ffa6324bd7cbb4da707312cd8"},
{file = "setproctitle-1.3.3-cp37-cp37m-win32.whl", hash = "sha256:7f1d36a1e15a46e8ede4e953abb104fdbc0845a266ec0e99cc0492a4364f8c44"},
{file = "setproctitle-1.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c9a402881ec269d0cc9c354b149fc29f9ec1a1939a777f1c858cdb09c7a261df"},
{file = "setproctitle-1.3.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ff814dea1e5c492a4980e3e7d094286077054e7ea116cbeda138819db194b2cd"},
{file = "setproctitle-1.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:accb66d7b3ccb00d5cd11d8c6e07055a4568a24c95cf86109894dcc0c134cc89"},
{file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:554eae5a5b28f02705b83a230e9d163d645c9a08914c0ad921df363a07cf39b1"},
{file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a911b26264dbe9e8066c7531c0591cfab27b464459c74385b276fe487ca91c12"},
{file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2982efe7640c4835f7355fdb4da313ad37fb3b40f5c69069912f8048f77b28c8"},
{file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df3f4274b80709d8bcab2f9a862973d453b308b97a0b423a501bcd93582852e3"},
{file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:af2c67ae4c795d1674a8d3ac1988676fa306bcfa1e23fddb5e0bd5f5635309ca"},
{file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:af4061f67fd7ec01624c5e3c21f6b7af2ef0e6bab7fbb43f209e6506c9ce0092"},
{file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:37a62cbe16d4c6294e84670b59cf7adcc73faafe6af07f8cb9adaf1f0e775b19"},
{file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a83ca086fbb017f0d87f240a8f9bbcf0809f3b754ee01cec928fff926542c450"},
{file = "setproctitle-1.3.3-cp38-cp38-win32.whl", hash = "sha256:059f4ce86f8cc92e5860abfc43a1dceb21137b26a02373618d88f6b4b86ba9b2"},
{file = "setproctitle-1.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:ab92e51cd4a218208efee4c6d37db7368fdf182f6e7ff148fb295ecddf264287"},
{file = "setproctitle-1.3.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c7951820b77abe03d88b114b998867c0f99da03859e5ab2623d94690848d3e45"},
{file = "setproctitle-1.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5bc94cf128676e8fac6503b37763adb378e2b6be1249d207630f83fc325d9b11"},
{file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f5d9027eeda64d353cf21a3ceb74bb1760bd534526c9214e19f052424b37e42"},
{file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e4a8104db15d3462e29d9946f26bed817a5b1d7a47eabca2d9dc2b995991503"},
{file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c32c41ace41f344d317399efff4cffb133e709cec2ef09c99e7a13e9f3b9483c"},
{file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbf16381c7bf7f963b58fb4daaa65684e10966ee14d26f5cc90f07049bfd8c1e"},
{file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e18b7bd0898398cc97ce2dfc83bb192a13a087ef6b2d5a8a36460311cb09e775"},
{file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:69d565d20efe527bd8a9b92e7f299ae5e73b6c0470f3719bd66f3cd821e0d5bd"},
{file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ddedd300cd690a3b06e7eac90ed4452348b1348635777ce23d460d913b5b63c3"},
{file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:415bfcfd01d1fbf5cbd75004599ef167a533395955305f42220a585f64036081"},
{file = "setproctitle-1.3.3-cp39-cp39-win32.whl", hash = "sha256:21112fcd2195d48f25760f0eafa7a76510871bbb3b750219310cf88b04456ae3"},
{file = "setproctitle-1.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:5a740f05d0968a5a17da3d676ce6afefebeeeb5ce137510901bf6306ba8ee002"},
{file = "setproctitle-1.3.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6b9e62ddb3db4b5205c0321dd69a406d8af9ee1693529d144e86bd43bcb4b6c0"},
{file = "setproctitle-1.3.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e3b99b338598de0bd6b2643bf8c343cf5ff70db3627af3ca427a5e1a1a90dd9"},
{file = "setproctitle-1.3.3-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ae9a02766dad331deb06855fb7a6ca15daea333b3967e214de12cfae8f0ef5"},
{file = "setproctitle-1.3.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:200ede6fd11233085ba9b764eb055a2a191fb4ffb950c68675ac53c874c22e20"},
{file = "setproctitle-1.3.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0d3a953c50776751e80fe755a380a64cb14d61e8762bd43041ab3f8cc436092f"},
{file = "setproctitle-1.3.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5e08e232b78ba3ac6bc0d23ce9e2bee8fad2be391b7e2da834fc9a45129eb87"},
{file = "setproctitle-1.3.3-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1da82c3e11284da4fcbf54957dafbf0655d2389cd3d54e4eaba636faf6d117a"},
{file = "setproctitle-1.3.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:aeaa71fb9568ebe9b911ddb490c644fbd2006e8c940f21cb9a1e9425bd709574"},
{file = "setproctitle-1.3.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:59335d000c6250c35989394661eb6287187854e94ac79ea22315469ee4f4c244"},
{file = "setproctitle-1.3.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3ba57029c9c50ecaf0c92bb127224cc2ea9fda057b5d99d3f348c9ec2855ad3"},
{file = "setproctitle-1.3.3-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d876d355c53d975c2ef9c4f2487c8f83dad6aeaaee1b6571453cb0ee992f55f6"},
{file = "setproctitle-1.3.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:224602f0939e6fb9d5dd881be1229d485f3257b540f8a900d4271a2c2aa4e5f4"},
{file = "setproctitle-1.3.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d7f27e0268af2d7503386e0e6be87fb9b6657afd96f5726b733837121146750d"},
{file = "setproctitle-1.3.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5e7266498cd31a4572378c61920af9f6b4676a73c299fce8ba93afd694f8ae7"},
{file = "setproctitle-1.3.3-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33c5609ad51cd99d388e55651b19148ea99727516132fb44680e1f28dd0d1de9"},
{file = "setproctitle-1.3.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:eae8988e78192fd1a3245a6f4f382390b61bce6cfcc93f3809726e4c885fa68d"},
{file = "setproctitle-1.3.3.tar.gz", hash = "sha256:c913e151e7ea01567837ff037a23ca8740192880198b7fbb90b16d181607caae"},
]
[package.extras]
test = ["pytest"]
[[package]]
name = "setuptools"
version = "69.0.3"
@ -4536,4 +4636,4 @@ files = [
[metadata]
lock-version = "2.0"
python-versions = "~3.12"
content-hash = "04ef13e2692c158e5eda1e89876a215746c56a891a161d8434d808dc12c0fc7a"
content-hash = "c5a36b528980277b07f80200da251a2bea31cc2b7d5438250706f23a825f3628"

View File

@ -133,6 +133,7 @@ pyyaml = "*"
requests-oauthlib = "*"
sentry-sdk = "*"
service_identity = "*"
setproctitle = "*"
structlog = "*"
swagger-spec-validator = "*"
tenant-schemas-celery = "*"

View File

@ -112,9 +112,7 @@ export class RoleAssignedObjectPermissionTable extends Table<RoleAssignedObjectP
item.permissions.filter((uperm) => uperm.codename === perm.codename).length > 0;
baseRow.push(
html`${granted
? html`<pf-tooltip
position="top"
content=${msg("Directly assigned")}
? html`<pf-tooltip position="top" content=${msg("Directly assigned")}
>✓</pf-tooltip
>`
: html`X`} `,

View File

@ -328,8 +328,7 @@ Requires authentik 2022.9
Configure how many gunicorn worker processes should be started (see https://docs.gunicorn.org/en/stable/design.html).
If running in Kubernetes, the default value is set to 2 and should in most cases not be changed, as scaling can be done with multiple pods running the web server.
Otherwise, authentik will use 1 worker for each 4 CPU cores + 1. A value below 2 workers is not recommended.
Defaults to 2. A value below 2 workers is not recommended. In environments where scaling with multiple replicas of the authentik server is not possible, this number can be increased to handle higher loads.
### `AUTHENTIK_WEB__THREADS`