artem

artem

What's good way to have limits for calling external APIs on a **monthly** or daily level?

Hi all

Need for exactly monthly limiting

I am learning Elixir (and Phoenix and LiveView) by creating a simple app that would fetch weather from external service and “creatively” present it (think “today is a bit warmer that yesterday” compared to “today is +17”).

At some point I’ll make the app public. Certainly for a hobby project I don’t want to pay much for the weather API and have to stay within free or cheap pricing tiers that is my Elixir backend should call external API no more than e.g. 1000 times per calendar month.

Precision/reliability needs

  • I will probably be fine with limiter being not super-precise, so it’s fine if limiting mechanism e.g. allows sometimes for 1050 per month and if it’s per 30 days from some arbitrary day, not exactly within a calendar month
  • On the other hand I won’t like if somebody uses monthly quota in one minute, better to leave some calls for the tomorrow visitors though good to allow small bursts.

So the ideal limiter would simultaneously apply something like:

  • no more than 1000 calls within 30 days or within a calendar month
  • no more than 100 calls a day
  • no more than 50 calls an hour
  • no more than 10 calls a minute
  • store whatever it needs in Postgres (okay to store it in-memory for a while, but syncs to DB are a must)
    • it’s a hobby project under active development, I don’t want to figure e.g. how to install and use Redis on gigalixir or fly.io while Postgres I am already using anyway
    • I don’t want to store state in-memory only - service is very likely to be restarted often. Actually in case of in-memory state even one restart mid-month could by accident overrun quota 2 times

What are the options?

I figured several options for proceeding and would love to get some advice from the more experienced folks.

  1. Hammer library (with a bit of massaging for combining the buckets) seems to allow for the rate limiting rules I am into. It doesn’t have a Postgres backend option, but maybe one is easy to write
  2. Create an own rate limiter/counter saving the log of requests (or the final counter) starting from mix phx.gen.context so the context would query call log table to tell the client how many calls are still allowed within month/day/hour?
    1. And if I’ll want to be “precise” over “fast” then maybe wrap it into a GenServer guaranteed to be run in 1 copy only
  3. Locate some other library that does approximately what I want. Maybe there’s something else besides Hammer that I just failed to locate so far.
  4. Something completely different?

What would you do in this kind of a situation?

Most Liked

gregvaughn

gregvaughn

I think you’re overthinking this. Write code that does what you described. I’d start with a database table that stores some token/label that represents a “bucket” of limits and a timestamp. Every time an API call is made you write an entry to that table. Before making the call you query for the limits – group by the various time intervals with a count of each and a having clause to enforce your desired constraints. It won’t be a trivial query (possibly window function or lateral join) but you’ll learn good things figuring that out. In the end it’ll be a single query.

artem

artem

Thank you, guys. I was also considering just writing a log of requests to the database and using SQL queries to check whether bucket is full or not. My main concern (that I should have stated more clearly in the beginning) was:

  • Am I reinventing the wheel? There could already be some known library to do just what I want or something very similar. Like if that Hammer library had a Postgres backend functional out of the box, it could be cheaper and more proper to just tune it to my case.

Now after this discussion it seems like my problem either isn’t common enough to have some known solutions or so simple that nobody bothered to make a library for it.

I guess most of hobbyists are using either totally free tiers or ones that have a clear spending limit. One I am likely to use is “metered”, so I could spend too much by accident. Probably it is not very common.

Four2

Four2

what would be easy to set up is a db chart of location, current temperature, date & time, clever remarks id
Then when the user lands on the page, a background query of that location’s date&time compare, then if it is within a certain amount of time since the last query of the temperature it displays the data you want on that chart line, if not, query the parse rss feed and update the temperature and the stored comments for the current weather, which would work well on a separate db table (like a remarks table with a unique column id) from the weather db table, a compare db table can be generated per location over time, and of course the remarks from another db chart.

Parsing data from a free xml/rss feed might be a better way of doing above instead of a web API.

Where Next?

Popular in Questions Top

chokchit
** (DBConnection.ConnectionError) connection not available and request was dropped from queue after 2733ms. You can configure how long re...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: The documentation above suggests that while ...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New
earth10
Hi, I’m just starting to build a side-project with Elixir and Phoenix and doing some basic test with Elixir alone. What strikes me is th...
New

Other popular topics Top

siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement