Skip to content

sdzyba/auctioning-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Auctioning

Basic workflow description: Admin schedules an auction using /admin/auctions endpoint. Here we determine when auction should start besides other params setting. Scheduling algorithm works in the following way:

  • define the limits in which auction can be scheduled (from and to). From is initialized as a current server time, to is (ride at - 1.hour). But we also adjust these timestamps depending on drivers' active hours, please see the specs
  • select all existing occupied time slots in from..to range. If there are no occupied slots, just schedule the auction at the middle of from..to range.
  • if there are occupied slots, split them into two pieces: before the middle point of from..to range and after middle point.
  • find possible after_middle and before_middle slots. We do this by defining all possible slots with a current_step and then we choose closest to the middle point by substracting a difference between occupied_after/occupied_before and all_after/all_before and a getting first_after/first_before. Please see the specs
  • is there are no slots available, divide the current_step (default is 60 seconds) by 2 and iterate again. Please see the specs
  • when starting time is determinated we persist an auction and schedule the StartAuctionWorker to Sidekiq on when the auction should start.
  • start_at calculation is locked by it's own separate lock (so we don't lock the entire auctions table) since we need to ensure the consistency of time slots.

StartAuctionWorker switches the auction status to started so when drivers are requesting the list of auctions they only the started ones. Also this worker schedules AuctionStepWorker, which would switch the price and reschedule itself on a next_step time. AuctionStepWorker would also switch the auction status to finished once auction's steps have reached the limit (steps limit and steps count in general are calculated based on auction's end_at - start_at). Here's specs

When driver wants to "pick up" and auction he sends a corresponding request. During this request processing we lock the auction record and assign it to driver. If there were multiple simultenious requests for the same auction, first one would be assigned and the rest of the requests would have an error response with "Already assigned" message.

Possible alternatives

  • Dynamically change start_at for each auction on every new auction arrival. A draft on how this could be implemented is here. Basically it's just selects all the slots, sorts them by priority (urgency) and reschedules them to be started as earlier as possible. While this solution sounds flexible, this flexibility brings another problems like not being able to "reschedule" anything in Sidekiq. So it'd either require some hacks to get it's working or just not to use Sidekiq at all and implement some separate listener process.
  • Do not schedule auctions in a "blind" way but measure the market load on each piece of a timeline. This might be achived by using some counters, I guess, like redis' counters, but I didn't dive into this solution enough.

Requirements

Build a small Ruby API / micro-service with a JSON or GRPC over HTTP interface to encapsulate an auctioning mechanism.

When a customer books a ride over Blacklane, we auction this ride to our network of drivers. Ideally we try to obtain the lowest price possible.

The auction can be triggered any time between the time of the booking and the time of the ride. The exact time an auction starts should be determined based on the following points:

  • the ride is assigned to a driver as soon as possible
  • drivers are active (assuming drivers check their phones between 8:00 and 20:00 every day)
  • there aren't so many auctions running at the same time - the market is not flooded with offers
  • $$$
  • anything else you find useful

The auction price starts with the lowest offering price (10% of customer price) and increases gradually with time - until it's accepted by a driver or when the offering price reaches customer price (breaking even). Every price increase in the auction's lifetime is called an auction step. All auction steps are available over the same period of time and provide the same price increase (time & price advance is linear).

Auctions should run over a short period of time (e.g. 30 minutes) and amount of steps (e.g. 5 steps). You can make these values configurable (but don't have to).

Endpoints

  1. As a Blacklane admin, create the auction.

Input:

  • customer price / break even price
  • time of ride / deadline
  • anything else you find useful

Output:

  • auction ID
  • auction start time
  • auction end time
  • auction initial price
  • auction final price
  1. As a driver, get a list of all the running auctions.

Output:

  • auction ID
  • auction step price
  • auction step expiry time (how long is the price available)
  1. As a driver, accept an auction.

Input:

  • auction ID
  • driver ID
  • anything else you find useful

Output:

  • some successful status code or error code with message

You can ignore authorization.

Guidelines

  • Preferred frameworks: any (e.g. Sinatra, Hobbit, Rails, Rack).
  • Preferred data storage: any (e.g. MySQL, Postgres, Redis).
  • Unit tests for the auctioning algorithms or the API interface (e.g. RSpec, Minitest)
  • These are just guidelines. You can take these tasks in any direction you want as long as it makes sense to you. Have fun!

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages