A retry loop cut each request below the time a slow but healthy server needs to answer. Every slow success turned into a timeout and a retry, and then a give-up, where the old code without a cut had simply waited.
Set a request cut above the server's worst healthy reply. Below it, slow successes become failures.
Size the total budget to fit a full cut plus one retry.
Size the total budget to fit a full cut plus one retry.