Search code examples
node.jsamazon-web-servicesarchitecturequeueamazon-sqs

Do I need FIFO SQS for jira like board view app


Currently I am running a jira like board-stage-card management app on AWS ECS with 8 tasks. When a card is moved from one column/stage to another, I look for the current stage object for that card remove card from that stage and add card to the destination stage object. This is working so far because I am always looking for the actual card's stage in the Postgres database not base on what frontend think that card belongs to.

Question:

  1. Is it safe to say that even when multiple users move the same card to different stages, but query would still happen one after the other and data will not corrupt? (such as duplicates)
  2. If there is still a chance data can be corrupted. Is it a good option to use SQS FIFO to send message to a lambda and handle each card movement in sequence ?
  3. Any other reason I should use SQS in this case ? or is SQS not applicable at all here?

Solution

  • The most important question here is: what do you want to happen?

    Looking at the state of a card in the database, and acting on that is only "wrong" if it doesn't implement the behavior you want. It's true that if the UI can get out of sync with the database, then users might not always get the result they were expecting - but that's all.

    Consider likelihood and consequences:

    • How likely is it that two or more people will update the same card, at the same time, to different stages?
    • And what is the consequence if they do?

    If the board is being used by a 20 person project team, then I'd say the chances were 'low/medium', and if they are paying attention to the board they'll see the unexpected change and have a discussion - because clearly they disagree (or someone moved it to the wrong stage by accident).

    So in that situation, I don't think you have a massive problem - as long as the system behavior is what you want (see my further responses below). On the other hand, if your board solution is being used to help operate a nuclear missile launch control system then I don't think your system is safe enough :)

    Is it safe to say that even when multiple users move the same card to different stages, but query would still happen one after the other and data will not corrupt? (such as duplicates)

    Yes the query will still happen - on the assumption:

    • That the database query looks up the card based on some stable identifier (e.g. CardID), and
    • that having successfully retrieved the card, your logic moves it to whatever destination stage is specified - implying there's no rules or state machine that might prohibit certain specific state transitions (e.g. moving from stage 1 to 2 is ok, but moving from stage 2 to 1 is not).

    Regarding your second question:

    If there is still a chance data can be corrupted.

    It depends on what you mean by 'corruption'. Data corruption is when unintended changes occur in data, and which usually make it unusable (un-processable, un-readable, etc) or useless (processable but incorrect). In your case it's more likely that your system would work properly, and that the data would not be corrupted (it remains processable, and the resulting state of the data is exactly what the system intended it to be), but simply that the results the users see might not be what they were expecting.

    Is it a good option to use SQS FIFO to send message to a lambda and handle each card movement in sequence ?

    A FIFO queue would only ensure that requests were processed in the order in which they were received by the queue. Whether or not this is "good" depends on the most important question (first sentence of this answer).

    Assuming the assumptions I provided above are correct: there is no state machine logic being enforced, and the card is found and processed via its ID, then all that will happen is that the last request will be the final state. E.g.:

    • Card State: Card.CardID = 001; Stage = 1.

    3 requests then get lodged into the FIFO queue in this order:

    1. User A - Move CardID 001 to Stage 2.
    2. User B - Move CardID 001 to Stage 4.
    3. User C - Move CardID 001 to Stage 3.

    • Resulting Card State: Card.CardID = 001; Stage = 3.

    That's "good" if you want the most recent request to be the result.

    Any other reason I should use SQS in this case ? or is SQS not applicable at all here?

    The only thing I can think of is that you would be able to store a "history", that way users could see all the recent changes to a card. This would do two things:

    • Prove that the system processed the requests correctly (according to what it was told to do, and it's logic).
    • Allow users to see who did what, and discuss.

    To implement that, you just need to record all relevant changes to the card, in the right order. The thing is, the database can probably do that on it's own, so use of SQS is still debatable, all the queue will do is maybe help avoid deadlocks.

    Update - RE Duplicate Cards

    You'd have to check the documentation for SQS to see if it can evaluate queue items and remove duplicates.

    Assuming it doesn't, you'll have to build something to handle that separately. All I can think of right now is to check for duplicates before adding them to the queue - because once that are there it's probably too late.

    One idea:

    • Establish a component in your code which acts as the proxy/façade for the queue.
    • Make it smart in that it knows about recent card actions ("recent" is whatever you think it needs to be).
    • A new card action comes it, it does a quick check to see if it has any other "recent" duplicate card actions, and if yes, decides what to do.

    One approach would be a very simple in-memory collection, and cycle out old items as fast as you dare to. "Recent", in terms of the lifetime of items in this collection, doesn't have to be the same as how long it takes for items to get through the queue - it just needs to be long enough to satisfy yourself there's no obvious duplicate.

    I can see such a set-up working, but potentially being quite problematic - so if you do it, keep it as simple as possible. ("Simple" meaning: functionally as narrowly-focused as possible).

    • Sizing will be a consideration - how many items are you processing a minute?

    • Operational considerations - if it's in-memory it'll be easy to lose (service restarts or whatever), so design the overall system in such a way that if that part goes down, or the list is flushed, items still get added to the queue and things keep working regardless.