Django signals debounce

23 Views Asked by At

In a project using Django's signal, when a series of UPDATEs of a particular model are executed, the processing of one SIGNAL is too heavy and causes discomfort to the user.

The process fired by SIGNAL does not need to be executed for each update when multiple UPDATEs are executed. For example, if UPDATE of model A is executed 20 times in one minute, there is no need to fire signal 20 times.

In light of the above, I think it would be better to implement something like debounce, where signal is fired only once even if multiple UPDATEs are executed in one minute. (We have already taken steps to reduce the number of signal firing conditions.)

Is it possible to run a debounce-like process in Django? Or is there a library that can accomplish this?

signal.py

@receiver(post_save, sender=ModelA)
def heavy_function1(
    sender: ModelA, instance: ModelA, *args, **kwargs
) -> None:
    result = calculate1(instance.attribute)
    update_modelB(result)

@receiver(post_save, sender=ModelA)
def heavy_function2(
    sender: ModelA, instance: ModelA, *args, **kwargs
) -> None:
    result = calculate2(instance.attribute)
    update_modelB(result)

@receiver(post_save, sender=ModelA)
def heavy_function3(
    sender: ModelA, instance: ModelA, *args, **kwargs
) -> None:
    result = calculate3(instance.attribute)
    update_modelB(result)

We already use django-model-util's FilldTracker to perform heavy processing only when certain attributes are updated.

model.py

class ModelA(models.Model):
    certain_attribute = models.IntegerField()
    _tracker = FieldTracker(
        fields=['certain_attribute']
    )

    @property
    def is_certain_attribute_changed(self) -> bool:
        return self._tracker.has_changed("certain_attribute")

signal.py

@receiver(post_save, sender=ModelA)
def heavy_function1(
    sender: ModelA, instance: ModelA, *args, **kwargs
) -> None:
    if created or instance.is_certain_attribute_changed:
        result = calculate1(instance.attribute)
        update_modelB(result)
0

There are 0 best solutions below