·4 min read

Announcing Python Serverless Redis and Ratelimiting SDKs

Tudor ZgîmbăuTudor ZgîmbăuSoftware Engineer (Guest Author)
Burak YılmazBurak YılmazSite Reliability Engineer @Upstash

As the Upstash team, our top priority is ensuring the happiness of our users. We aim to make the user experience easy and smooth, with our SDKs playing a significant role in achieving this goal. So far, all of our SDKs are in JavaScript and TypeScript, given their popularity. However, with the rising popularity of AI-based applications, we've noticed an increasing number of people using Upstash Redis in Python applications. We aim to simplify things for Python developers too. As a first step, we are releasing the official SDK for Redis in Python, which will utilize our HTTP-based API. Thanks to this HTTP-based API, it's perfect for serverless runtimes, which can be challenging for TCP connections.

Secondly, we're porting our most popular and arguably most useful SDK to Python - the Upstash Rate Limiting SDK. This SDK has become an essential component of applications requiring application-level rate limiting. Rate limiting is becoming an increasingly significant requirement, particularly for applications that consume AI APIs. These APIs are expensive in terms of both cost and resources. Thus, limiting users on an API key or IP basis is critical.

Here's what you can do with the rate-limiting SDK:

  • Limit user activity by the number of requests within a certain time period.
  • Set an identifier to limit a user in a unique way (e.g., user-id, API key, IP address).
  • Choose from different strategies, including fixed window, sliding window, and token bucket.
  • Block (or wait) the request until it is allowed to process.
  • Set different limits for different plans.
  • Monitor usage with an analytics dashboard

Packages: upstash-redis and upstash-ratelimit

Getting Started

Before using the SDKs, make sure you set the following environment variables:

  • UPSTASH_REDIS_REST_URL
  • UPSTASH_REDIS_REST_TOKEN

You can find those variables in Upstash console.

Upstash Redis SDK

from upstash_redis import Redis
 
redis = Redis.from_env()
 
redis.set("foo", "bar")
 
print("Set value:", redis.get("foo"))
from upstash_redis import Redis
 
redis = Redis.from_env()
 
redis.set("foo", "bar")
 
print("Set value:", redis.get("foo"))

Or, you can use upstash-redis in async context as well!

from upstash_redis.asyncio import Redis
from asyncio import run
 
async def main():
    redis = Redis.from_env()
    await redis.set("foo", "bar")
    print("Set value in async context:", await redis.get("foo"))
 
run(main())
from upstash_redis.asyncio import Redis
from asyncio import run
 
async def main():
    redis = Redis.from_env()
    await redis.set("foo", "bar")
    print("Set value in async context:", await redis.get("foo"))
 
run(main())

You can have a look at GitHub to see different client options.

Upstash Ratelimit SDK

from upstash_ratelimit import Ratelimit, FixedWindow
from upstash_redis import Redis
from time import sleep
 
ratelimit = Ratelimit(
    redis=Redis.from_env(),
    limiter=FixedWindow(max_requests=2, window=10),
    prefix="upstash-ratelimit",
)
 
identifier = "api"
response = ratelimit.limit(identifier)
 
if not response.allowed:
    print("Unable to process at this time")
else:
    sleep(1) # do_expensive_calculation()
    print("Here you go!")
from upstash_ratelimit import Ratelimit, FixedWindow
from upstash_redis import Redis
from time import sleep
 
ratelimit = Ratelimit(
    redis=Redis.from_env(),
    limiter=FixedWindow(max_requests=2, window=10),
    prefix="upstash-ratelimit",
)
 
identifier = "api"
response = ratelimit.limit(identifier)
 
if not response.allowed:
    print("Unable to process at this time")
else:
    sleep(1) # do_expensive_calculation()
    print("Here you go!")

Or,you can use it in async context as well!

from upstash_ratelimit.asyncio import Ratelimit, FixedWindow
from upstash_redis.asyncio import Redis
from asyncio import run, sleep
 
ratelimit = Ratelimit(
    redis=Redis.from_env(),
    limiter=FixedWindow(max_requests=2, window=10),
    prefix="upstash-ratelimit",
)
 
async def main():
    identifier = "api"
    response = await ratelimit.limit(identifier)
 
    if not response.allowed:
        print("Unable to process at this time")
    else:
        await sleep(1) # do_expensive_calculation()
        print("Here you go!")
 
run(main())
from upstash_ratelimit.asyncio import Ratelimit, FixedWindow
from upstash_redis.asyncio import Redis
from asyncio import run, sleep
 
ratelimit = Ratelimit(
    redis=Redis.from_env(),
    limiter=FixedWindow(max_requests=2, window=10),
    prefix="upstash-ratelimit",
)
 
async def main():
    identifier = "api"
    response = await ratelimit.limit(identifier)
 
    if not response.allowed:
        print("Unable to process at this time")
    else:
        await sleep(1) # do_expensive_calculation()
        print("Here you go!")
 
run(main())

upstash-ratelimit provides 3 different algorithms to use for rate-limiting, each having its pros and cons. You can read more about the differences in the README.

We also provide two methods for enforcing limits:

  • limit(), which returns an object containing allowed field and some additional metadata about an identifier's request
  • block_until_ready(), which allows waiting for a request to pass in a certain timeout.

You can also get some metadata about an identifier's state:

  • get_remaining(): Returns the number of requests left for the given identifier.
  • get_reset(): Returns the UNIX timestamp in seconds when the remaining requests will be reset or replenished.

Closing words

If you have any questions, please reach out to Upstash on Discord or Twitter.

If you encounter any issues or have any suggestions, you can also file an issue on GitHub