Implementing the Transactional Outbox pattern with Hangfire

แชร์
ฝัง
  • เผยแพร่เมื่อ 7 พ.ย. 2024

ความคิดเห็น • 60

  • @MilanJovanovicTech
    @MilanJovanovicTech  6 หลายเดือนก่อน +2

    Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
    Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt

  • @diegomelgar2696
    @diegomelgar2696 หลายเดือนก่อน

    Hi there, is it possible to use another database instance for recurring jobs to save outbox messages records instead of reading/persisting the current database in order to decrease latency from API requests?

  • @gustavopinheiro5503
    @gustavopinheiro5503 2 หลายเดือนก่อน

    Thanks for the video ! I have already implemented the outbox pattern but following your other video using Quartz. I have a question about the outbox implementation for domain events in general:
    Would it make sense to save in the database just the failed domain events? I mean, we could send the domain events right away after saving the changes and if some handler fails to handle the event, we could save the necessary info for later retry of that specific event and handler.

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 หลายเดือนก่อน

      That could increase the latency of the original request. And we'd be publishing the events twice, so we have to start thinking about duplicating some side effects

  • @Nekr0n666
    @Nekr0n666 6 หลายเดือนก่อน +3

    Great video! But doesn't Hangfire have a DisableConcurrentExecution attribute you can use instead of database locks?

    • @MilanJovanovicTech
      @MilanJovanovicTech  6 หลายเดือนก่อน +1

      Which also uses locks: github.com/HangfireIO/Hangfire/blob/main/src/Hangfire.Core/DisableConcurrentExecutionAttribute.cs#L51

  • @SalmanShafiq-y3q
    @SalmanShafiq-y3q 6 หลายเดือนก่อน +3

    Thanks Milan ❤
    You have already implemented it using Quartz. What do u think which one is better between of these?
    Could plz make any video on ef core migration and which approach should to use between code first and db first?

    • @MilanJovanovicTech
      @MilanJovanovicTech  6 หลายเดือนก่อน +3

      | What do u think which one is better between of these?
      I slightly prefer Quartz for recurring jobs, as I find it easier to configure. I like Hangfire for on-demand background jobs, though.
      | ef core migration and which approach should to use between code first and db first?
      Yes, planning to make one!

    • @xantari79
      @xantari79 5 หลายเดือนก่อน

      Hangfire console add on makes it even more attractive then quartz if you need a UI for your jobs as it will render realtime logging information

  •  5 หลายเดือนก่อน +1

    Almost all popular databases provide functionality for getting triggers when data was changed. We could use such triggers for outbox processing. Instead of the background process, we get notifications on new events.

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 หลายเดือนก่อน

      How would you retrigger a retrigger in case you fail to process it?

    •  5 หลายเดือนก่อน

      @@MilanJovanovicTech Just forward it to a message bus and use queue retries on failing. Also then you can add it to a database table to implement inbox pattern and allow quickly accept events from the bus. The key is both outbox and inbox can be implemented using polling or by change detection capture (CDC)

  • @nestenius
    @nestenius 5 หลายเดือนก่อน

    Great video Milan.
    What do you suggest to use when I have multi-tenant application using Finbuckle Multitenant? I cannot configure hangfire storage on Startup as I get the actual tenant and its connectionstring in httpcontext.

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 หลายเดือนก่อน +1

      Haven't worked with Funbuckle at all

  • @juanpablocansecorios3421
    @juanpablocansecorios3421 3 หลายเดือนก่อน

    Recently I discovered your channel and learn a lot thanks to your videos.
    With this video in particular I have a question of the use case of the outbox pattern.
    For example, if you are building a real-time application let’s say a twitter clone and you send a retweet to a post, once the retweet has been processed for a command then dispatch an event to notify the clients of the numbers of retweets had increased.
    This example can be archived with MediatR and HangFire?
    This could be a valid example of the use cases of the outbox pattern?

    • @MilanJovanovicTech
      @MilanJovanovicTech  3 หลายเดือนก่อน +1

      We could definitely use it like this. But Outbox also introduces lag. With real-time applications such as social networks we may want to consider a different approach. On the other side, a few seconds of lag from user action to clients finding out may not be an issue.

  • @middleyat5950
    @middleyat5950 13 วันที่ผ่านมา

    A question: How can I know which tenant to take to execute a background job (I have a method that brings the dates of upcoming maintenance for a vehicle); when it is raised in background job the tenant comes out in null, how can I enter the tenant? It is an onion architecture. thanks

  • @antonmartyniuk
    @antonmartyniuk 5 หลายเดือนก่อน +1

    While Hangfire is a cool library I would implement this OutBox messages processing using Background Service with Periodic timer and won't bother about concurrent executions

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 หลายเดือนก่อน

      I think that's too simplistic. I'd want something more robust. But if it works, it works.

    • @antonmartyniuk
      @antonmartyniuk 5 หลายเดือนก่อน +1

      @@MilanJovanovicTech simple and reliable, you can have resiliency with Polly with retries, everything that you can come up with. In this case, scheduling library doesn't add any value. First, you can't miss an outbox message scan with my approach. Second, when you restart the app, the background job will trigger.
      It's not a criticism but another point of view. I would use scheduling library if I have tasks that occur everyday, every few days or every few hours. But not in the case of scanning database for outbox messages every few seconds/minutes

    • @xantari79
      @xantari79 5 หลายเดือนก่อน

      If your app is running on a multi node cluster how are you accounting for concurrent execution?

  • @pvlzh
    @pvlzh 6 หลายเดือนก่อน +1

    Thanks for the great video.
    It would be interesting to look at how to correctly implement jobs that should be launched after some time from business logic.
    For example, after my entity is created in the handler in my business logic, I need this entity to change after a day (for example, the status has changed so that it is considered overdue).

    • @MilanJovanovicTech
      @MilanJovanovicTech  6 หลายเดือนก่อน

      Hangfire let's you schedule delayed jobs, so that's an avenue I would explore

  • @Fikusiklol
    @Fikusiklol 5 หลายเดือนก่อน

    Hey there!
    I assume using SKIP LOCKED gives no ordering guarantees and should be used when ordering doesnt matter.
    I would say either use a database level lock in a distributed systems or just split those outbox messages to different tables based on some specific type.
    Please correct me if im wrong.
    Nonetheless, good content :)

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 หลายเดือนก่อน

      SKIP LOCKED should respect the ORDER BY clause

  • @madukakuogbonnaya6646
    @madukakuogbonnaya6646 6 หลายเดือนก่อน

    If you were using EFCore would you have needed to lock any rows or would EFCore do that automatically

    • @MilanJovanovicTech
      @MilanJovanovicTech  6 หลายเดือนก่อน

      No, EF Core doesn't do locking

    • @madukakuogbonnaya6646
      @madukakuogbonnaya6646 6 หลายเดือนก่อน

      @@MilanJovanovicTech thanks for the response, please clarify further does this mean I shouldn't use efcore with Hangfire as it won't handle concurrency issues, or is there a way I can use it safely.

  • @DaveLegend-g8o
    @DaveLegend-g8o 6 หลายเดือนก่อน

    instead of using a lock, will rabbit mq be used instead to ensure a record is not processed twice?

    • @MilanJovanovicTech
      @MilanJovanovicTech  6 หลายเดือนก่อน

      There's two problems to solve - not publishing twice, and not consuming twice

  • @TheAzerue
    @TheAzerue 5 หลายเดือนก่อน

    What do you think of Pros and Cons of using OutBox Pattern using MassTransit. I have used the word "using" since its already implemented in MassTransit. In which scenarios one would use MassTransit for outbox and cases Hangfire like in this video ?

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 หลายเดือนก่อน +1

      I need to dedicate some time to talk about that! Thanks for the reminder :)

  • @SalmanShafiq-y3q
    @SalmanShafiq-y3q 5 หลายเดือนก่อน

    Would you like to make a video how to register service in DI using static functional approach by features?

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 หลายเดือนก่อน

      Perhaps this? th-cam.com/video/tKEF6xaeoig/w-d-xo.html

  • @nove1398
    @nove1398 6 หลายเดือนก่อน

    Can we use system.text to decode the outbox messages?

    • @MilanJovanovicTech
      @MilanJovanovicTech  6 หลายเดือนก่อน +1

      Yes, but it's limited for serializing so I just use Newtonsoft

  • @masterdimar
    @masterdimar 6 หลายเดือนก่อน

    Why you put the commit outside the foreach? Why not in every message?

    • @MilanJovanovicTech
      @MilanJovanovicTech  6 หลายเดือนก่อน

      You commit the transaction once

    • @masterdimar
      @masterdimar 5 หลายเดือนก่อน

      @@MilanJovanovicTech yes, but i want to understantd why you are commiting once all the message from the foreach were sent and not for every message

    • @kaozryan
      @kaozryan 4 หลายเดือนก่อน

      @@masterdimar Its because once he started a transaction, you cant commit for every operation. Once one commit has been done, if you try to commit again an error will be thrown.

  • @Gilgameshx
    @Gilgameshx 6 หลายเดือนก่อน

    Hangfire is a powerful library, but i prefer to use azure function timer

    • @MilanJovanovicTech
      @MilanJovanovicTech  6 หลายเดือนก่อน

      Why?

    • @Gilgameshx
      @Gilgameshx 6 หลายเดือนก่อน

      @@MilanJovanovicTech You can do the same without applying too many configurations, also to use the hangfire UI console it require to be authenticate and maybe with some privileges as well, yet hangfire is very nice, useful and worth to give a try.

  • @JavierAcrich
    @JavierAcrich 6 หลายเดือนก่อน

    SKIP LOCKED should be the default behavior. It doesn't make sense to lock ALL rows in the table if you are selecting just a few.

    • @MilanJovanovicTech
      @MilanJovanovicTech  6 หลายเดือนก่อน +1

      It doesn't lock ALL rows, just the ones you select in that query.
      If you're doing a SELECT without a WHERE statement, well, that's on you...

  • @dariuszlenartowicz
    @dariuszlenartowicz 6 หลายเดือนก่อน

    Hangfire, Quartz for that simple task? :)

  • @feinirl
    @feinirl 6 หลายเดือนก่อน

    great video tho

  • @baranacikgoz
    @baranacikgoz 6 หลายเดือนก่อน

    I love hangfire and using it. But it is an overkill for an outbox processor. It could be easily done with IHostedService and there will never be concurrency issue. Hangfire shines most when we don't not know when to trigger the job at design time, such as sending a welcome email in bg when a new user is registered to the system.
    Btw. Thanks for the video, excellent job.

    • @ВладиславРудаков-е4з
      @ВладиславРудаков-е4з 6 หลายเดือนก่อน +2

      But the application instance itself may die, then we will lose everything that was in the background
      And if there are many instances of the same application, then IHostedService is especially not suitable
      Correct me if I'm wrong.

    • @baranacikgoz
      @baranacikgoz 6 หลายเดือนก่อน

      @@ВладиславРудаков-е4з
      1 - There is nothing to lose, this outbox messages are already persisted in db before. We just fetch them, publish them and update their state to "Processed". So you won't loose anything in case of application failure. You might just republish same event after application restart but that's the same case with Hangfire, no difference.
      2 - The same concern applies alsp when using Hangfire, no difference again. It is wiser that you run all background related things in a separate app, process regardless of how much webapi instance you have. Of course, you should configure a single app to be hangfire server also, not every instances

    • @MilanJovanovicTech
      @MilanJovanovicTech  6 หลายเดือนก่อน

      I still consider Hangfire a general-purpose background job scheduling tool

  • @tonystoynev7969
    @tonystoynev7969 6 หลายเดือนก่อน +1

    Interesting video! But is it a coincidence that Nick Chapsas recently uploaded a video about HangFire ?

    • @MilanJovanovicTech
      @MilanJovanovicTech  6 หลายเดือนก่อน +2

      *Checks notes*: recorded this on February 21st... Can post proof 😁

    • @MilanJovanovicTech
      @MilanJovanovicTech  6 หลายเดือนก่อน +3

      Heads up, also recorded an OpenTelemetry video with Aspire Dashboard back in February... That's coming out next week 😁

    • @MilanJovanovicTech
      @MilanJovanovicTech  6 หลายเดือนก่อน +4

      And you can also clearly see logs in the video dated to February 21st: prnt.sc/2rERFH6aqXRq

    • @tonystoynev7969
      @tonystoynev7969 6 หลายเดือนก่อน +1

      Thanks for the evidences. I will know for the future videos that the ideas behind them is your! Your are one of my favourite content creators and I wish you much success