outposts: improve performance by running related check in worker, fix tokens being left over on outpost delete
This commit is contained in:
parent
45699a1a69
commit
18da7565c2
|
@ -1,51 +1,28 @@
|
||||||
"""passbook outpost signals"""
|
"""passbook outpost signals"""
|
||||||
from django.db.models import Model
|
from django.db.models import Model
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save, pre_delete
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from structlog import get_logger
|
from structlog import get_logger
|
||||||
|
|
||||||
from passbook.lib.utils.reflection import class_to_path
|
from passbook.lib.utils.reflection import class_to_path
|
||||||
from passbook.outposts.models import Outpost, OutpostModel
|
from passbook.outposts.models import Outpost
|
||||||
from passbook.outposts.tasks import outpost_send_update
|
from passbook.outposts.tasks import outpost_post_save
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Outpost)
|
|
||||||
# pylint: disable=unused-argument
|
|
||||||
def ensure_user_and_token(sender, instance: Model, **_):
|
|
||||||
"""Ensure that token is created/updated on save"""
|
|
||||||
_ = instance.token
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save)
|
@receiver(post_save)
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def post_save_update(sender, instance: Model, **_):
|
def post_save_update(sender, instance: Model, **_):
|
||||||
"""If an OutpostModel, or a model that is somehow connected to an OutpostModel is saved,
|
"""If an Outpost is saved, Ensure that token is created/updated
|
||||||
|
|
||||||
|
If an OutpostModel, or a model that is somehow connected to an OutpostModel is saved,
|
||||||
we send a message down the relevant OutpostModels WS connection to trigger an update"""
|
we send a message down the relevant OutpostModels WS connection to trigger an update"""
|
||||||
if isinstance(instance, (OutpostModel, Outpost)):
|
outpost_post_save.delay(class_to_path(instance.__class__), instance.pk)
|
||||||
LOGGER.debug(
|
|
||||||
"triggering outpost update from outpostmodel/outpost", instance=instance
|
|
||||||
)
|
|
||||||
outpost_send_update.delay(class_to_path(instance.__class__), instance.pk)
|
|
||||||
return
|
|
||||||
|
|
||||||
for field in instance._meta.get_fields():
|
|
||||||
# Each field is checked if it has a `related_model` attribute (when ForeginKeys or M2Ms)
|
|
||||||
# are used, and if it has a value
|
|
||||||
if not hasattr(field, "related_model"):
|
|
||||||
continue
|
|
||||||
if not field.related_model:
|
|
||||||
continue
|
|
||||||
if not issubclass(field.related_model, OutpostModel):
|
|
||||||
continue
|
|
||||||
|
|
||||||
field_name = f"{field.name}_set"
|
@receiver(pre_delete, sender=Outpost)
|
||||||
if not hasattr(instance, field_name):
|
# pylint: disable=unused-argument
|
||||||
continue
|
def pre_delete_cleanup(sender, instance: Outpost, **_):
|
||||||
|
"""Ensure that Outpost's user is deleted (which will delete the token through cascade)"""
|
||||||
LOGGER.debug("triggering outpost update from from field", field=field.name)
|
instance.user.delete()
|
||||||
# Because the Outpost Model has an M2M to Provider,
|
|
||||||
# we have to iterate over the entire QS
|
|
||||||
for reverse in getattr(instance, field_name).all():
|
|
||||||
outpost_send_update(class_to_path(reverse.__class__), reverse.pk)
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ from typing import Any
|
||||||
|
|
||||||
from asgiref.sync import async_to_sync
|
from asgiref.sync import async_to_sync
|
||||||
from channels.layers import get_channel_layer
|
from channels.layers import get_channel_layer
|
||||||
|
from django.db.models.base import Model
|
||||||
from structlog import get_logger
|
from structlog import get_logger
|
||||||
|
|
||||||
from passbook.lib.utils.reflection import path_to_class
|
from passbook.lib.utils.reflection import path_to_class
|
||||||
|
@ -42,11 +43,54 @@ def outpost_controller_single(outpost_pk: str, deployment_type: str, outpost_typ
|
||||||
|
|
||||||
|
|
||||||
@CELERY_APP.task()
|
@CELERY_APP.task()
|
||||||
def outpost_send_update(model_class: str, model_pk: Any):
|
def outpost_post_save(model_class: str, model_pk: Any):
|
||||||
|
"""If an Outpost is saved, Ensure that token is created/updated
|
||||||
|
|
||||||
|
If an OutpostModel, or a model that is somehow connected to an OutpostModel is saved,
|
||||||
|
we send a message down the relevant OutpostModels WS connection to trigger an update"""
|
||||||
|
model: Model = path_to_class(model_class)
|
||||||
|
try:
|
||||||
|
instance = model.objects.get(pk=model_pk)
|
||||||
|
except model.DoesNotExist:
|
||||||
|
LOGGER.warning("Model does not exist", model=model, pk=model_pk)
|
||||||
|
return
|
||||||
|
|
||||||
|
if isinstance(instance, Outpost):
|
||||||
|
LOGGER.debug("Ensuring token for outpost", instance=instance)
|
||||||
|
_ = instance.token
|
||||||
|
return
|
||||||
|
|
||||||
|
if isinstance(instance, (OutpostModel, Outpost)):
|
||||||
|
LOGGER.debug(
|
||||||
|
"triggering outpost update from outpostmodel/outpost", instance=instance
|
||||||
|
)
|
||||||
|
outpost_send_update(instance)
|
||||||
|
return
|
||||||
|
|
||||||
|
for field in instance._meta.get_fields():
|
||||||
|
# Each field is checked if it has a `related_model` attribute (when ForeginKeys or M2Ms)
|
||||||
|
# are used, and if it has a value
|
||||||
|
if not hasattr(field, "related_model"):
|
||||||
|
continue
|
||||||
|
if not field.related_model:
|
||||||
|
continue
|
||||||
|
if not issubclass(field.related_model, OutpostModel):
|
||||||
|
continue
|
||||||
|
|
||||||
|
field_name = f"{field.name}_set"
|
||||||
|
if not hasattr(instance, field_name):
|
||||||
|
continue
|
||||||
|
|
||||||
|
LOGGER.debug("triggering outpost update from from field", field=field.name)
|
||||||
|
# Because the Outpost Model has an M2M to Provider,
|
||||||
|
# we have to iterate over the entire QS
|
||||||
|
for reverse in getattr(instance, field_name).all():
|
||||||
|
outpost_send_update(reverse)
|
||||||
|
|
||||||
|
|
||||||
|
def outpost_send_update(model_instace: Model):
|
||||||
"""Send outpost update to all registered outposts, irregardless to which passbook
|
"""Send outpost update to all registered outposts, irregardless to which passbook
|
||||||
instance they are connected"""
|
instance they are connected"""
|
||||||
model = path_to_class(model_class)
|
|
||||||
model_instace = model.objects.get(pk=model_pk)
|
|
||||||
channel_layer = get_channel_layer()
|
channel_layer = get_channel_layer()
|
||||||
if isinstance(model_instace, OutpostModel):
|
if isinstance(model_instace, OutpostModel):
|
||||||
for outpost in model_instace.outpost_set.all():
|
for outpost in model_instace.outpost_set.all():
|
||||||
|
|
Reference in New Issue