ZucchiniZe

ZucchiniZe

New to elixir, having trouble with interfacing with a shaky external API

I’m trying to build a website that imports data from an external API that is unbearably slow as well as being quite unreliable. Right now while piecing it together I have everything (somewhat) working with a manual invocation of the functions in IEx and then fixing the inevitable errors that happen.

The API that I’m querying has a hard limit on the amount of resources you can get per request so I’ve solved that by using Enum.map and Task.async + Task.await to get the responses and then am using an ecto multi to handle the bulk insertion of the entities. But since the entities are interlinked from the API as well as in my database schema. I need a consistent way to not fail or automatically fix the errors of when a linked resource doesn’t exist.

I’m also going to try and have this on some sort of cron job or repeating background job to go through and refresh the data from the external API.

Is there some sort of way to implement an automatic retry for failed requests and some sort of thing that reacts to missing data and requests it from the API?

Most Liked

stefanchrobot

stefanchrobot

If I got that correctly, your app uses an external API to fetch data, transforms that into your own format, saves that in DB and then exposes that through your own API. The problem is that the external API is really unreliable. As a consequence, you don’t really have an option to implement it via hot calls.

So what I’m suggesting is that you “clone” the external database. You have options here:

  1. dump the responses from the API straight into the DB: the advantage here is that you can easily change your own JSON schema (add more attributes, etc.), since the external data sits in your DB
  2. store the transformed entities in the DB: the advantage here is speed (negligible)
  3. do both

Seems like the problem that you need to solve here is to decide what data and when to pull it from the external API.

As to what:

  • can you store everything locally? what’s the estimated data set? can you afford this?
  • does your application need all the data?

As to when:

  • does the external API has web hooks or any other notification mechanism?
  • does the external API has an incremental endpoint (i.e. give me what changed since timestamp)?
  • if you need to poll for data, what’s the acceptable timespan? how is this affected by quota?

Depending on the answers, the whole thing might event turn infeasible (I hope not!).

I’d implement this export as a worker that runs continuously in the background under it’s own supervision tree. As to how organize this - it really depends on the structure of the data and what the external API gives you. But my first approach would be a process that has a queue of messages, where each message represents a resource to be fetched. For each message, a task is spawned to fetch the data. If it fails, the message is resent to try again. Some additional process would also periodically request fetching of all resources.

outlog

outlog

you can do retries with tesla

https://hexdocs.pm/tesla/Tesla.Middleware.Retry.html

the missing data part, sounds domain specific so I think you would have to roll your own, maybe against a changeset, and if it’s invalid you load in the missing data from the api…

for the cron part you can use quantum GitHub - c-rack/quantum-elixir: Cron-like job scheduler for Elixir

stefanchrobot

stefanchrobot

I would consider making a mirror of the external system, i.e. dump the data (JSON, XML, whatnot) into your database as is; put that into a worker and handle external API failures there… Then add a separate worker that would transform and upload the data to the destination. This might make for a cleaner design and better performance.

stefanchrobot

stefanchrobot

The doesn’t seem to be an issue since the process is going to give you eventual consistency. The exported data is always stale (unless you can update the data in both systems as part of a single transaction or you can block updates in the old system), so it’s best to embrace this fact. You could make the staleness window smaller if you’d have notification from the old API + fast response times + no API quota, but that’s not the case.

stefanchrobot

stefanchrobot

I’m happy to be of any help. Also I’m into MCU lately, so I’ll keep an eye on your project :slight_smile:

Where Next?

Popular in Questions Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
Kagamiiiii
Student & New to elixir. Nice language. I want to convert a english character, e.g. “a”, which is stored in a variable, to it’s asci...
New
sacepums
Hey guys. I'm new to elixir and im really stocked about it. But I ran into a bit of problem - I need to convert a date sting, for examp...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
Mooodi
Given a string, how can I get access to its character by index? Enum.at("my_string", 2) doesn't work. Or rather, not char, but a substr...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Other popular topics Top

joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
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
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 42633 214
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
273 38985 115
New

We're in Beta

About us Mission Statement