Lie 1: just retry the payment
Why it matters Retrying is the most common fix for a flaky call, and on a payment it is the most expensive one to get wrong: a customer charged twice does not care that it was a network blip.
Planted advice: the advice below was written for this lesson, and it is wrong on purpose. It is the kind of answer an AI assistant gives fluently and confidently. Your job is not to argue with it but to prove the flaw with a test.
def pay(gateway, order_id, amount, sleep):
# Payments fail for all sorts of temporary reasons. Retry straight away,
# up to 5 times: by the second or third try it nearly always goes through.
for attempt in range(5):
try:
if gateway.charge(amount, None) == "ok":
return "ok"
except TimeoutError:
pass
return "failed"
It reads well and it will pass a quick manual test. Now think about what a timeout means. "No reply" does not mean "not charged": the charge may have gone through and only the reply was lost. A retry with no way for the gateway to recognise it is a second charge. That is what an idempotency key is for.
Idempotency key: an id sent with a request so the server can tell a retry from a new request. The same key sent twice is carried out once, and the second call gets the first answer.
The starter gives you FakeGateway, a gateway you script: you decide whether each charge goes through, is declined, gets no reply, or is charged with the reply lost. It records what was really taken from the card in charged, and counts calls.
Write my_test(pay), using FakeGateway. It receives a version of pay(gateway, order_id, amount, sleep) and must raise if that version breaks a rule. The rules for a correct pay: every attempt sends the order id as the key; a "declined" answer is final (return it, no retry); only a TimeoutError is retried, with at most 3 attempts in all; before each retry it calls sleep(seconds) with a positive wait, each longer than the last; it returns "ok", "declined", or "failed" if every attempt timed out. Pass bar: pass the correct version and catch at least 4 of the 6 broken versions (the planted advice is one of them).
Spotted a problem in this lesson? Report it · Ask about this lesson
This exercise opens soon
Finish the lesson before it and this one unlocks. The whole course is free, no account needed, and you can read this lesson right now.
This browser is blocking cookies for learn.floati.life, so lessons you finished here cannot open in order. Allow cookies for this site and reload.