ZucchiniZe
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?
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 12 to 3- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
stefanchrobot
That was my initial thinking. I don’t have enough experience, but I think that GenStage might be a better fit here:
http://tomasztomczyk.com/2017/01/17/genstage-for-processing-jobs.html
ZucchiniZe
Yeah, I originally wrote this about a year ago in python using a web scraper with mixed results, it worked but was expensive to keep running plus it required quite a bit of manual intervention. This was something that I thought elixir/phoenix could solve really well so it became my pet project for learning. So you are suggesting that I have a GenServer that starts and stops tasks based on calls coming from either the ui or some sort of scheduler? Would you suggest that the
Tasks be under a supervision tree?Thank you so much! This is exactly what I was looking for, the way that I was doing felt very limited and required a lot of repeated code. Time to migrate all of the other schema parsing stuff to this new format that is so much cleaner and nicer. Thank you so much
!
stefanchrobot
The problem you’re solving sounds similar to writing a web crawler. I’d start with a GenServer that manages a set of
Tasks.So you’re mapping one schema to another. Seems like there are two options: write it by hand or roll-out/use an existing mapping lib. That would DRY the code up by making it more more declarative, i.e. for each key of each schema entity define what to do with it (sketch):
It might be the case that’s it’s not worth the hassle, though.
ZucchiniZe
The MCU is great! I loved infinity war so much and I absolutely cannot wait for the new Ant Man and The Wasp movie.
If you’d like a tour of my code please feel free to pm me.
As for the worker process, would a genserver work in this case, or would something else be optimal? Do you also have any suggestions on how to normalize/validate the input data, because right now I have it working but it feels a lot less than elegant and I feel that there is some method that I could be using that would make it a lot better (here’s an example of how I’m handling it currently).
stefanchrobot
I’m happy to be of any help. Also I’m into MCU lately, so I’ll keep an eye on your project
ZucchiniZe
Yes, I am attempting to clone the database because after a proof of concept I’ve realized that hot calls were completely out of the window because of the unreliability as well as the extreme speed, while designing the proof of concept I implemented a caching middleware for the http client that I am using which temporarily solves the issue with speed and could be considered dumping the responses to a database. I’m not sure if storing the items in the database or storing them using ets tables would be better, but just going off of gut intuition I’m leaning towards storing them in the database so they can be persisted across restarts.
For What:
For When:
One other thing that is causing a lot of anguish for me is the consistency of the data supplied from the API, as per their schema, nothing is a required field (that is including the id for the resource! thankfully they all do have id’s) and handling the inconsistencies is a bit of an issue but I think I’ve solved it and just need to work on the implementation a bit more.
Also, thank you so so so much for your help! It has been really really nice to get detailed feedback on my problems
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:
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:
As to when:
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.
ZucchiniZe
I feel like I’m not really understanding what you are saying. So I should just get the data from the API, dump that into a database, and then spawn a whole separate worker to transform it and put into the database? What do you mean by “put that into a worker and handle external API failures there”? I already have an implementation working that sort of does that.
Because the API is limited to 100 results at a time I do some parallel requests and then flatten that response into a list of maps that I then run through an
api_to_changesetfunction that takes the raw api result and then transforms it into a usable changeset that I put into anEcto.Multito batch insert into the database.But currently because of the flakiness of the API I get
:connect_timeout’s from hackney which the exponential retry system attempts to combat.link to implementation
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.
ZucchiniZe
The thing is that this data is constantly changing and needs to be updated on a consistent basis. I have implemented an exponential retry system which handles the failed requests well-ish. I still don’t know how to make it work consistently though.