How to limit the frequency of calling third-party interfaces in code

background

When calling a third-party interface, the common problem is that the calling frequency is too fast, which leads to a series of problems: it may be blocked by IP; it may be blocked; it may also be restricted and other problems.

Solutions

The easiest way: limit the frequency of calls within a time period

The ratelimit implementation controls the frequency of calling the API

For example, the following test code uses multi-threaded simulation request to call test2()the function

import time
import threading

def test2():
    time.sleep(3)
    print('调用了函数')


def run_func():
    print('模拟普通请求...')
    test2()


if __name__ == '__main__':
    all_t = []
    for i in range(10):
        t = threading.Thread(target=run_func)
        all_t.append(t)

    for n in all_t:
        n.start()

    for k in all_t:
        k.join()

In the above test code, the function is called at the same time in the 10 started threads test2(), which can be understood as requesting the API 10 times within 1 second. Next, we need to introduce ratelimitthe library to control the frequency of calls.

import time
from ratelimit import limits

@limits(calls=1, period=1)
def test2():
    time.sleep(3)
    print('调用了函数')

By default, 15 requests are allowed within 15 minutes, and excess requests will be discarded. Setting it here calls=1,period=1means that only one request is allowed within 1s.

However, when running the above code, an error occurred in some of the threads ratelimit.exception.RateLimitException: too many calls. Why?

increase blocking wait

As mentioned above, when the number of requests exceeds the set value within the set time, other requests will be discarded. Therefore, RateLimitExceptionthe case where an error is returned needs to be handled.

Add a decorator to block the excess request

import time
from functools import wraps

from ratelimit import RateLimitException


def sleep_and_retry(func):
    @wraps(func)
    def wrapper(*args, **kargs):
        while True:
            try:
                return func(*args, **kargs)
            except RateLimitException as exception:
                time.sleep(exception.period_remaining)
    return wrapper

result

After adding the above decorator, the excess requests are also blocked, and the requests can be responded normally.

full code

import threading
import time
from functools import wraps

from ratelimit import limits, RateLimitException


def sleep_and_retry(func):
    @wraps(func)
    def wrapper(*args, **kargs):
        while True:
            try:
                return func(*args, **kargs)
            except RateLimitException as exception:
                time.sleep(exception.period_remaining)
    return wrapper


@sleep_and_retry
@limits(calls=1, period=1)
def test2():
    time.sleep(3)
    print('调用了函数')


def run_func():
    print('模拟普通请求...')
    test2()


if __name__ == '__main__':
    all_t = []
    for i in range(10):
        t = threading.Thread(target=run_func)
        all_t.append(t)

    for n in all_t:
        n.start()

    for k in all_t:
        k.join()

Guess you like

Origin blog.csdn.net/qq_42349944/article/details/129880244