skip to Main Content

For this question, I’m particularly struggling with how to structure this:

  1. User accesses website
  2. User clicks button
  3. Value x in database increments

My issue is that multiple people could potentially be on the website at the same time and click the button – I want to make sure each user is able to click the button, and update the value and read the incremented value too, but I don’t know how to circumvent any synchronisation/concurrency issues.

I’m using flask to run my website backend, and I’m thinking of using MongoDB or Redis to store my single value that needs to be updated.

Please comment if there is any lack of clarity in my question, but this is a problem I’ve really been struggling with how to solve.

Thanks 🙂

2

Answers


  1. To solve this problem I would suggest you follow a micro service architecture.

    A service called worker would handle the flask route that’s called when the user clicks on the link/button on the website. It would generate a message to be sent to another service called queue manager that maintains a queue of increment/decrement messages from the worker service.

    There can be multiple worker service instances running concurrently but the queue manager is a singleton service that takes the messages from each service and adds them to the queue. If the queue manager is busy the worker service will either timeout and retry or return a failure message to the user. If the queue is full a response is sent back to the worker to retry n number of times, and you can count down that n.

    A third service called storage manager is run every time the queue is not empty, this service sends the messages to the storage solution (whatever mongo, redis, good ol’ sql) and it will ensure the increment/decrement messages are handled in the order they were received in the queue. You could also include a time stamp from the worker service in the message if you wanted to use that to sort the queue.

    Generally whatever hosting environment for flask will use gunicorn as the production web server and support multiple concurrent worker instances to handle the http requests, and this would naturally be your worker service.

    How you build and coordinate the queue manager and storage manager is down to implementation preference, for instance you could use something like Google Cloud pub/sub system to send messages between different deployed services but that’s just off the top of my head. There’s a load of different ways to do it, and you’re in the best position to decide that.

    Without knowing more details about what you’re trying to achieve and what’s the requirements for concurrent traffic I can’t go into greater detail, but that’s roughly how I’ve approached this type of problem in the past. If you need to handle more concurrent users at the website, you can pick a hosting solution with more concurrent workers. If you need the queue to be longer, you can pick a host with more memory, or else write the queue to an intermediate storage. This will slow it down but will make recovering from a crash easier.

    You also need to consider handling when messages fail between different services, how to recover from a service crashing or the queue filling up.

    EDIT: Been thinking about this over the weekend and a much simpler solution is to just create a new record in a table directly from the flask route that handles user clicks. Then to get your total you just get a count from this table. Your bottlenecks are going to be how many concurrent workers your flask hosting environment supports and how many concurrent connections your storage supports. Both of these can be solved by throwing more resources at them.

    Login or Signup to reply.
    1. redis, I think you can use redis hincrby command, or create a distributed lock to make sure there is only one writer at the same time and only the lock holding writer can make the update in your flask framework. Make sure you release the lock after certain period of time or after the writer done using the lock.
    2. mysql, you can start a transaction, and make the update and commit the change to make sure the data is right
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search