doogs

doogs

Best way to structure an Auction Website/Platform

I have a project which will basically be an auction platform.
At any given time there could be 1000-10,000 active auctions, but there will only ever be around 10 bidders on each auction.
Auctions would typically last around 10min up to 2 hours.
Typically all auctions and bidding in the system would happen within a 4 hour window, otherwise all auctions are closed.

What is the best way to structure this type of application?

My initial thinking is to have Auctions and Bids stored in the database.
For every Auction there will also be a genserver which would have an internal tic (Process.send_after) which would check every second to see if the auction should have ended yet.
Once it has ended it could close the auction and stop bidding.

If the genserver crashes it could rebuild from the database.
And It would reduce calls to the server with the internal tic which is checking if the auction has ended instead of querying the db.
From there I could also accept bids into the genserver and only store that data once it has ended, further reducing load on the DB if I wanted.

Are there any drawback or risks with this scenario?

Without genserver, I guess I could have a cron that runs every second(ish) and updates all auction status.
Would this be more simple? does this scale better or worse?

Is there any easier way, or better way to do this given the scale I am looking at?

Lastly, if this was to scale to 50,000 auctions and hundreds of bidders.does this change things at all?

Most Liked

kip

kip

ex_cldr Core Team

A couple of thoughts (I’m not an auction expert):

  1. I would think bidders expect a high precision on the start and end times, so a process_after/2 is likely not the right mechanism to determine if an auction is open of not

  2. Preserving order of bids is presumably very important in an auction

  3. Latency of bid acceptance into the bidding queue is important - ie predictable and consistent queuing and ordering under load (for which of course the BEAM is well suited)

Intuitively I think of this as:

  1. A GenServer per auction to provide the ordering
  2. Phoenix PubSub or similar to broadcast state of the auction to all bidders with low latency and soft real-time characteristics
  3. Each bid has a time stamp applied on entry to the system and when pulling a bid of the queue (in the handle_call) then use the time stamp to decide if the bid is within the valid period of the auction. This also gives you a better audit record of bids and the times they entered the system

I see complexity in the area of:

  1. A valid bid is entered and its the new high bid
  2. You want to store all the bids for audit purposes, this takes time
  3. You want to broadcast the high bid to the other bidders in real time as fast as possible
  4. (2) and (3) have a big of conflict in order to keep consistent state, reliably and also broadcast the highest bid as fast as possible.

My understanding is that in auctions, the action can get fast and furious in the closing minutes/seconds hence a good solution to (4) might be important. I’m not the person to help you with that :slight_smile:

srowley

srowley

I got pretty far building an auction app for my fantasy football league (so, you know, very critical that we achieve high precision! :slight_smile:). It was a learning exercise so I built it with the idea that it could handle multiple auctions simultaneously.

I did not bother to implement timestamps but otherwise it looked a lot like what is described here and that idea makes sense. The only thing I would add is that I used ETS for persisting the data beyond the GenServers. Obviously ETS can die if you lose the machine or the BEAM otherwise crashes, but I can imagine that being your first stop given the speed with which I understand one can read/write to ETS. You could also still have a separate database that you update asynchronously (only reading from that if the entire BEAM crashes or to dump to a data warehouse for querying) as a second backup.

Point being you will still have the consistency problem, but the durability tradeoff is just that, I think. I assumed (but did not test) that going back and forth to ETS resulted in much reduced latency with only a minimal loss of durability relative to using a separate database. Of course if you get to a scale that requires you to distribute your auction processes across multiple nodes, ETS would be off the table.

kip

kip

ex_cldr Core Team

You’re in the last 2 seconds of your auction. There are 100 bidders online. Some might even be doing algorithmic bidding. The most important thing is that each bidder has the current bid price in as near to immediate time as possible. The second thing is that you can accept as many bids as quickly as possible with similar latency and response so all bidders are treated the same. Third thing is to keep auction integrity - everyone sees the same information at the same time, each bid is treated equally, bids are accepted to the last microsecond, the highest bidder wins etc etc.

Synchronising persistent state at the same time as delivering on those core auction requirements is challenging.

I think thats what @srowley and I are both saying (and apologies if I misinterpreted your reply).

I would not expect 10_000 auctions itself to be a special consideration.

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
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
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
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
JulienCorb
I am trying to implement my new.html.eex file to create new posts on my website. new.html.eex: <h1>Create Post</h1> <%= ...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
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 records...
New

Other popular topics Top

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
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
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
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
Lily
In templates/appointment/index.html.eex: <%= for appointment <- @appointments do %> <tr> <td><%= appoi...
New
jaysoifer
Is there a way to rollback a specific migration and only that one (“skipping” all the other ones)? Would mix ecto.rollback -v 200809061...
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
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
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

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement