3

I have 3 signal functions and one is getting stuck in a loop when it is called. It is called when an object inside of a model class is updated on the Django Admin page...

# models.py
class Item(models.Model):
    ...
    foo = models.BooleanField(
        default=False,
        editable=True,
        blank=True,
        help_text='Blah Blah...'    
    )
# signals.py
@receiver(pre_save, sender=Item)
def foobar(sender, instance, **kwargs):
    try:
        pass
    except:
        pass

I literally put pass in each try and except with a call to a log just to see if it is repeating even without code in them, and it is. Constantly with no end. This happens using an if / else statement, too, instead of try / except.

How the heck can I stop the signal from getting stuck in a loop? It is supposed to send an email each time, but now when the object is updated, the user gets blasted with infinite emails until I reboot Django.

I am really at a loss here...

BTW, this doesn't happen on my test server, only on my live/staging server.

EDIT:

If you are viewing this in the future, this is how I debugged my issue.

Look for anything that is running/hitting your server and potentially sparking a signal to run. For me, it was a specific object that was set as the sender for a signal to run, and each time the webhook I was using was causing a function to run, which was modifying the specific sender object.

PythonReactor
  • 483
  • 4
  • 18
  • you mean `except Exception` right? because except alone happen with every action. I don't understand how your mailing system work but you shouldn't use except alone – Linh Nguyen Aug 04 '20 at 09:10
  • @LinhNguyen color me embarrassed. I didn’t even think of that. So just to clarify, you’re saying the except will run after every action in the try? Or run at the end of the try? – PythonReactor Aug 04 '20 at 09:12
  • i think this answer explain better than what i'm explaining https://stackoverflow.com/a/730778/11225821 – Linh Nguyen Aug 04 '20 at 09:15
  • I will check that out @LinhNguyen, thank you. However, I must mention, my other signals are setup the same way and run no issue. – PythonReactor Aug 04 '20 at 09:16
  • had you tried debug on staging server yet? just add print to the try catch case and see if it print alot, if it doesn't then there must be something wrong with the sending email function – Linh Nguyen Aug 04 '20 at 09:17
  • @LinhNguyen I have. I place a lot of printing loggers. I’m literally placing ‘pass’ and ‘pass’ under both try and except. With the exception of print logs under ‘try’. And with that, it’s constantly looking through the try, never ending the signal call when I update my object. – PythonReactor Aug 04 '20 at 09:20
  • pre_save is called on save(), do you see any case of infinite save() loop in your code with Item model? yes pre_save will trigger on create or update too – Linh Nguyen Aug 04 '20 at 09:21
  • The same occurs if I use post_save, too. How should I check for infinite save() calls? – PythonReactor Aug 04 '20 at 09:22
  • can you provide the code that you either update or create an Item object to the post? – Linh Nguyen Aug 04 '20 at 09:23
  • That’s the issue I mentioned in my post. The object is updated in the Admin page. I literally edit a user, check the checkbox (Boolean value) and press “save” on the user object. It is an extension of the User – PythonReactor Aug 04 '20 at 09:25
  • i tried replicate with your model and signal but i can't reproduce the infinite loop, pretty strange if you ask me – Linh Nguyen Aug 04 '20 at 09:50

1 Answers1

0

So I am hesitant to post this as an "Answer," as this potentially only gives reason to my own issue here, but I have figured out what is going on...

I recently connected a Webhook to my Django app, one that is constantly hitting it and updating information... I have fixed my webhook function to only hit the Model Object (above, it is Class Item) so that it lowers the number of times the signals run.

However, this is the literal fix for the signal running to completion:

# signals.py
...

obj = sender.objects.get(pk=instance.pk)

# We are checking if the instance value is different than what the object value
# is. Remember, this is PRE_SAVE, so the object should be different than the
# instance
if instance.variable and not obj.variable:
    ...

...
PythonReactor
  • 483
  • 4
  • 18