0

I have some code which checks for data coming from Stripe's Webhook. Now I got some code that queries my database to check if the payment has been confirmed. I am trying to write a function that checks my database to see if the payment has been confirmed, if the payment has not yet been confirmed, the program should wait 5 seconds and then check again, checking a maximum of 5 times. If after the fifth try the payment still does not show as confirmed, then I need to redirect the user.

This is because my code might execute faster than Stripe returns their webhook response to my server.

Current code below. How do I create the 'loop' on the if statement?

def accepted(request, payment_id):

    r = Usertasks.objects.all().filter(user=request.user).filter(randomURL=payment_id).values("TaskPostedToNetwork")
    e = Usertasks.objects.all().filter(user=request.user).filter(randomURL=payment_id).values("PaymentConfirmed")
    if r == "False" and e == "yes":
        print("true")
    else:
        return redirect('dashboard:index')
    return render(request, 'request.html',)
Matthias Wiehl
  • 1,799
  • 16
  • 22
Phillip
  • 295
  • 1
  • 3
  • 12

2 Answers2

1

You can do this by wrapping your query/check logic in a for loop. Since you want to perform these actions a maximum of 5 times, you can do a for loop over range(5) and since on success you use return, the loop will stop on success. Thus a maximum of 5 times.

In the other case, when you'll check again instead of breaking out of the function, you can call time.sleep(5) to stop execution and wait for 5 seconds.

If the loop completes (executes the block 5 times without getting success and exiting) then you'll reach the return redirect... line.

Like so:

import time

def accepted(request, payment_id):
    seconds_between_calls = 5
    max_calls = 5
    for _ in range(max_calls):
        r = Usertasks.objects.all().filter(user=request.user).filter(randomURL=payment_id).values("TaskPostedToNetwork")
        e = Usertasks.objects.all().filter(user=request.user).filter(randomURL=payment_id).values("PaymentConfirmed")
        if r == "False" and e == "yes":
            print("true")
            return render(request, 'request.html',)
        else:
            # try again
            time.sleep(seconds_between_calls)    
    return redirect('dashboard:index') # if max_calls hit
Henry Woody
  • 14,024
  • 7
  • 39
  • 56
  • Let's say I change the `print("true")` part out for a `return`. Will that also stop the for loop? – Phillip Mar 21 '19 at 21:41
  • Yeah if you put a `return` in that place, you'll exit the function as well. But then you wouldn't get the "try again" type of logic – Henry Woody Mar 21 '19 at 21:42
  • Well the meaning is that once the IF statement is True it should return the user to another page and quit the retry loop. I assume this would still work then, right? – Phillip Mar 21 '19 at 21:44
  • oh, so do you want to try again if the `if` is False (and you get to the `else` statement) and redirect to 'dashboard:index' if you get False more than 5 times? – Henry Woody Mar 21 '19 at 21:46
  • You're absolutely correct. Pardon my explanation skills. – Phillip Mar 21 '19 at 21:47
  • no worries. I made an edit, is that what you're looking for? – Henry Woody Mar 21 '19 at 21:50
  • Is it still possible to redirect on the `else` part if it reaches the max limit of 5 retries? – Phillip Mar 21 '19 at 21:52
  • That's what happens here basically. So if you get through the whole loop (5 times without getting a True in that `if` condition), you'll exit the loop and move to the next line, which is `return redirect...` – Henry Woody Mar 21 '19 at 21:53
  • Running `sleep` will halt the thread, though. If OP wants to still do things while waiting, async is the way to go. – jhpratt Mar 21 '19 at 21:59
  • @HenryWoody I just noticed that the code in the If statement is ran 5 times and not only once. Do you mind sparing me your time to help me with that? – Phillip Mar 22 '19 at 12:03
  • @HenryWoody Never mind, I fixed it myself. Just added `break`. – Phillip Mar 22 '19 at 12:07
  • 1
    @Phillip it should only be hit once, if at all, `return` works like `break` but a bit stronger – Henry Woody Mar 22 '19 at 16:24
0

You could define a variable for the num of retries and the sleep time per try. (Currently you have 5 and 5 but it may change and you don't want to manually edit each occurrence later on.)

There after use a for loop on the num of retries and time.sleep(time_per_try). Note: You'll have to import time for this.

perennial_noob
  • 459
  • 3
  • 14