DDD – Managing Long Running Background Threads and Reporting Progress

cdesign-patternsdomain-driven-design

Title says most of it. I have found surprising little information about this. I have a long running operation of which the user wants to see the progress (as in, item x of y processed). I also need to be able to pause and stop the operation. (Stopping doesn't rollback the items already processed.)

The thing is, it's not that each item takes a long time to get processed, it's that that there are usually a lot of items. And what I've read about so far is that it's somewhat of an anti-pattern to put something like a queue in the DB. I currently don't have any messaging system in place, and I've never worked with one either.

Another thing I read somewhere is that progress reporting is something that belongs in the application layer, but it didn't go into the details. So having said all this, what I have in mind is the following.

  • User request with list of items enters the application layer.
  • Application layer gets some information from the domain needed to process the items.
  • Application layer passes the items and the information off to some domain service (should the implementation of this service belong in the infrastructure layer?)
  • This service spins up a worker thread with callbacks for both progress reporting and pausing/stopping it.
  • This worker thread will process each item in it's own UoW. This means the domain information from earlier needs to be stored in some DTO.
  • Since nothing is really persisted, the service should be singleton and thread safe
  • Whenever a user requests a progress report or wants to pause/stop the operation, the application layer will ask the service.

Would this be a correct solution? Or am I at least on the right track with this? Especially the singleton and thread safe part makes the whole thing feel icky.

Best Answer

These types of operational concerns are the responsibility of the application layer and as such they are agnostic of DDD. The application layer delegates to the domain layer which can be implemented using DDD. It is atypical for a domain service to spin up worker threads and deal with processing status. Instead, it should be focused on implementing domain logic that does not naturally belong in an aggregate, entity or value object. Management of threads and processing status should be handled by the application layer because it is an operational concern, not a domain concern. There are multiple ways to implement long running processes with progress information. Using threads within an AppDomain is only one way to go. For example, if fault tolerance and distribution is required, it is best to place work items into a durable queue and have a message handler which processes these messages by delegating to the domain layer. Such an implementation is depicted in Request/Acknowledge/Poll With ASP.NET WebAPI and NServiceBus. Regardless of implementation of this application layer responsibility, the domain remains the same.

Related Topic