thephpleague / omnipay

A framework agnostic, multi-gateway payment processing library for PHP 5.6+
http://omnipay.thephpleague.com/
MIT License
5.91k stars 925 forks source link

How a "429 Too Many Requests" or equivalent should be handled? #632

Open devnix opened 3 years ago

devnix commented 3 years ago

Hi! I'm improving an existing Redsys driver for Omnipay.

Currently, I have a queue of refunds for my project. A cronjob gets the unprocessed refunds of the queue, updates their status, logs the error if it happens, and marks it as executed.

I have an edge case with Redsys. When they consider that we are going too fast (they don't specify any rate limit) they give a 200 HTTP code with a custom status in the response with the code "SIS0295", which could be the HTTP equivalent of 429. In this case the error is logged but the refund is not marked as executed.

The thing is in the driver if I get an error I will throw an InvalidResponseException, but I don't know of a standard way to differentiate an error which will always occur against an error that I can fix by waiting for a few minutes and then trying again.

I've been poking around the PayPal driver, but I've not found any reference for handling 429 Unprocessable Entity - RATE_LIMIT_REACHED or similar.

devnix commented 3 years ago

Thinking out loud, I'm between this ones in RefundResponse::__construct()

// Best one? I see that there is no way to get the original request or access to
// the configured RequestFactory, so I'm forced to create my own Request class
// just to fake the data, which smells to me like a design problem
throw new \Omnipay\Common\Http\Exception\RequestException('Too many requests', $request);
throw new \Omnipay\Common\Http\Exception\NetworkException('Too many requests', 429);
throw new \Omnipay\Common\Exception\InvalidRequestException('Too many requests', 429);
throw new Omnipay\Common\Exception\RuntimeException('Too many requests', 429); // Or default 0 code

I've been looking through several Omnipay gateways and I don't find any implementing this, so I'm very concerned about how to proceed so my gateway would remain compatible with the rest of the existing ones.

EDIT: Maybe throwing Omnipay\Common\Http\Exception\RequestException at RefundRequest::sendData() before creating RefundResponse would be the best approach?

devnix commented 3 years ago

Maybe a good implementation on the omnipay-common side would be an \Omnipay\Common\Http\Exception\TooManyRequestsHttpException extending \Omnipay\Common\Http\Exception\InvalidRequestException in the line of the symfony/http-kernel component.

WDYT @judgej?