Implementing the Transactional Outbox Pattern from Scratch

Поділитися
Вставка
  • Опубліковано 29 лис 2024

КОМЕНТАРІ •

  • @MilanJovanovicTech
    @MilanJovanovicTech  4 дні тому +1

    Get the source code for this video for FREE → the-dotnet-weekly.kit.com/outbox-pattern
    Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
    Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt

  • @Paul-uo9sv
    @Paul-uo9sv 15 годин тому

    This is my favorite youtube channel. Thanks Milan. I got my I.T. developers at my company on it now... listen I'm going to get my company to buy your lessons with their money... should be great, need to talk to my IT managers.. thanks!!!

    • @MilanJovanovicTech
      @MilanJovanovicTech  8 годин тому

      Did you check the next video? 😁
      BF discount is up until December 2nd (but I also offer bigger discounts for multiple seats)

  • @radustoleru9109
    @radustoleru9109 День тому +1

    this is also called dual write problem
    and I was using this pattern without knowing that its called outbox and your explanation is really good, everything well pointed
    at enterprise level most likely a CDC tool will be used plus something like kafka, but that's another story ))

  • @RMarjanovic
    @RMarjanovic 2 дні тому

    Looks like you found a workaround for the polymorphic deserialization. Love it!

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 дні тому

      Works nicely because MassTransit can publish it without any issues. Ends up being a much cleaner solution.

    • @MaxwellHay
      @MaxwellHay День тому

      This “workaround” was widely used in deserialization until the famous insecure type handling was discovered. System.text.json purposely doesn’t support it. So use with caution.

  • @MSylar
    @MSylar 3 дні тому +4

    Isn't it possible that the transaction CommitAsync in the OutboxProcessor throws an exception? If I am not mistaken in this (edge-)case the messages would be published, but in the database they remain unprocessed. Do you have any advice to handle this scenario?

    • @MilanJovanovicTech
      @MilanJovanovicTech  3 дні тому +4

      Retry. Consumer gets a duplicate, so it should be idempotent (as I mentioned in the video). The likelihood a commit fails is fairly low, but it's a valid concern.

    • @John.Oliver
      @John.Oliver 3 дні тому +2

      @@MilanJovanovicTech A better solution here would be to update the outbox_message record prior to publishing the message. This way, if the write to the DB fails, no message is published and if the publishing of the message fails, the DB update can be rolled back (because of transaction).
      Not only does this keep the whole process atomic, but you can still implement a publish retry (no point if DB update unless deadlock occurs).

  • @Parchie
    @Parchie 2 дні тому +1

    Hi @MilanJovanovicTech, what keyboard are you using? I love the sound of it in your videos, thanks!

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 дні тому

      Logitech G413 Carbon (red lights)
      Edit: This one -> www.logitechg.com/en-gb/products/gaming-keyboards/g413-mechanical-gaming-keyboard.html
      I also got the light one as a backup. Only use it every now and then.

  • @dotnetMasterCSharp
    @dotnetMasterCSharp 2 дні тому

    This is awesome part in real world projects

  •  3 дні тому

    Great video. ❤ The example shows it for integration messages. I guess it should be the same for domain events. I'm looking forward to the next parts, especially the Outbox processor supporting horizontal scaling of services. Will we see an implementation with CDC or will we continue polling with a background process?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 дні тому +1

      Coming out this Friday. The CDC implementation may take some time. :)

  • @susantamaji2941
    @susantamaji2941 4 дні тому +1

    Just simply thank you sir.

  • @PippiTheLongSock
    @PippiTheLongSock День тому

    Hi, Milan! Great video as always! I have a suggestion for a future video. Can you show how to use the outbox support which is built-into MassTransit. The implementation relies on ef core so you might need to create a different demo, though. Still, last time I checked Chris Patterson claimed that he has managed to achieve exactly once message delivery. Another cool feature is that the messages are being published immediatelly after a successful transaction, so you don't have any latency between the db polls. Anyways, just an idea, keep up the good work!

    • @MilanJovanovicTech
      @MilanJovanovicTech  8 годин тому +1

      I will at some point, once I'm done with this series. Need to research how it all works under the hood. I don't want to just give you a magic solution.

  • @playvirtul5588
    @playvirtul5588 4 дні тому +1

    Thank you for the video! Is it worth writing your own implementation of an outbox if you can use the ready-made one from MassTransit? What are the advantages of both approaches?

    • @MilanJovanovicTech
      @MilanJovanovicTech  4 дні тому

      If the MT outbox gives you all you need, go for it. No need to take up the responsibility.
      If you want fine-grained control, then consider building it yourself. I'm not sure how we could scale the MT outbox (is it as simple as adding another background worker?)

    • @MiningForPies
      @MiningForPies 2 дні тому

      MT outbox is in memory.

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 дні тому

      @@MiningForPies Can also use database (AddEntityFrameworkOutbox)

  • @RISHIBANDYOPADHYAY-v2p
    @RISHIBANDYOPADHYAY-v2p День тому +1

    Hey, can we use this concept while using mongo db ?

  • @twitchizle
    @twitchizle 4 дні тому +1

    Awesome. Easy. Clean.

  • @pilotboba
    @pilotboba 20 годин тому

    Since you are using MassTransit, it already supports this pattern. So you don't need to roll a lot of this yourself. Nick Chapass did a YT video on this BTW.

    • @MilanJovanovicTech
      @MilanJovanovicTech  8 годин тому

      This isn't a lot of code to get it working. Granted, I'd need to add some resilience and retries, possibly some alerting or a DLQ. I think events (messages) are valuable information in a system, and I'd like to own that aspect of my architecture completely.

  • @MahbuburRahman-uc7np
    @MahbuburRahman-uc7np 3 дні тому

    Good video. Btw, How are you getting the values inline during debugging in Visual Studio?

  • @Midicifu
    @Midicifu 3 дні тому

    Hi thanks for the great content, one question, what is your approach to hydrate new services that will depends on data from other services (eventual consistency), I have seen some use grpc or even http call to get the data by batches in a consumer background service... i know kafka is an option an I already use it as service bus but I dont want to store to much info in kafka, another approach is CDC but for me this is overkill 😅, so what is your decision in this. Thanks!

    • @MilanJovanovicTech
      @MilanJovanovicTech  3 дні тому

      How about good old DB backups? Take the data from one service, and just dump it in another.
      Then, we'll need to implement continuous updates between the services. You can use something like messaging with the Outbox for that part.

    • @Midicifu
      @Midicifu 3 дні тому +1

      @MilanJovanovicTech I will keep in mind that option, for now this open a new question about how can I implement this in the CI CD pipeline but that's is great because I am studying and give me the opportunity to implement this approach. Many thanks!

  • @wannadie9950
    @wannadie9950 3 дні тому

    hi milan ! im wondering whats the reasons of you using singleton datasource instead of singleton connection factory ?

  • @danielmarkov7964
    @danielmarkov7964 3 дні тому

    What If I want to Publish without awaiting it (quick response to client)? Does the task will fault? Or what are the best practices to do such operations?
    TPL dataflow? Hangfire?
    Thanks 💪🏼

    • @MilanJovanovicTech
      @MilanJovanovicTech  3 дні тому

      It doesn't have to fault, but how will you handle if it does? In other words, how do we tell the DB that it should retry the job?

    • @danielmarkov7964
      @danielmarkov7964 3 дні тому

      @ I’m not talking about the current situation, I’m talking about a flow where I want to “fire and forget” publish without awaiting it and return 202 to the client, which is the best way to do so?

  • @ahmedameen2
    @ahmedameen2 3 дні тому

    Hi @milan how to solve the issue of the order of the messages? If you configure the message broker to use single queue it's becoming bottleneck and un scalable

    •  3 дні тому

      Delivery order cannot be guaranteed in that scenario. Integration events must be designed to withstand being processed out of order. Design is the key. You cannot rely on your broker for these matters.

    • @ahmedameen2
      @ahmedameen2 3 дні тому

      In very basic scenario where entity created then updated how to adjust the integration events so data is consistent?

    •  3 дні тому +1

      @@ahmedameen2 Your view is too crudish. It seems like you are doing data transferring between services instead of communicating state changes of your different bounded contexts. This is the wrong approach for using a service broker.

    • @MilanJovanovicTech
      @MilanJovanovicTech  3 дні тому +1

      You'd get "at best" in order delivery. What you can do is create a buffer for incoming messages on the consumer, where you can sort them before processing them. But even that isn't perfect. I would explore also what options the broker offers for message ordering guarantees.

    • @ahmedameen2
      @ahmedameen2 3 дні тому

      ​@@MilanJovanovicTechI heard from you in other article talking about inbox pattern that could help. I think we need dedicated video for it

  • @joga_bonito_aro
    @joga_bonito_aro 15 годин тому

    I'm awake now... Flashbanged by light mode.

  •  3 дні тому +1

    Maybe I'm overthinking this but if you say that the consumer should be able to handle duplicate messages in case of DB update failure in your loop... You might as well handle this without the outbox pattern by publishing the message before the order gets inserted... And say the consumer should handle the case where there's no order.

    • @MilanJovanovicTech
      @MilanJovanovicTech  3 дні тому +1

      Then it's not an event. Events are facts. They can only become facts after "what causes the event" already happens. In our case, the initial database transaction.
      Second, scaling that approach is not very fun. What if we have: save order, reserve inventory, process payment, ship package. Do we publish all these messages to the respective services before we actually save the order?

    •  3 дні тому

      @MilanJovanovicTech OK, I can see how we can argue about nuances and meanings of various cases. But the takeaway is that yes, I'm indeed overthinking this and you are right.
      I also think that most message processing services have features that prevent duplicates. Perhaps it's best to leave these concerns to them since it's their job anyway.

    • @MilanJovanovicTech
      @MilanJovanovicTech  3 дні тому +1

      And most do have duplicate dedection - in a short time window. But we can have a couple of seconds (or more) pass between retries, and this can be treated as a legitimate message.
      So unless a broker explicitly supports deduplication with some message ID - it will be up to the consumer.

  • @AnkurSingh-nh1qv
    @AnkurSingh-nh1qv 3 дні тому +1

    Hi milan, i m facing a problem and not able to comprehend a solution, I have one product available , if one user select the product and trying to buy , but at same time another request comes and see that similar product because the inventory is not updated yet , how to handle this situation , there is a order , inventory and payment microservice pls can u make video on this with full details how to handle when inventory db update fails and also when payment fails

    • @MilanJovanovicTech
      @MilanJovanovicTech  3 дні тому +2

      Explore pessimistic and optimistic locking:
      - Pessimistic: www.milanjovanovic.tech/blog/a-clever-way-to-implement-pessimistic-locking-in-ef-core
      - Optimistic: www.milanjovanovic.tech/blog/solving-race-conditions-with-ef-core-optimistic-locking

    • @meJevin
      @meJevin 3 дні тому

      in the place responsible for finishing the order you need to verify with the database, where you store the quantity, that you still have that item. using a distributed lock, when finishing the order, should also prevent others from interfering.