1

I have a running order for 2 handlers Deleting and Reordering pictures and would like some advises for the best solution.

On the UI some pictures are deleted, the user clicks on the deleted button. The whole flow, delete command up to an event handler which actually deletes the physical files is started.

Then immediately the user sorts the remaining pictures. A new flow from reorder command up to the reordering event handler for the file system fires again.

Already there is a concurrency problem. The reordering cannot be correctly applied without having the deletion done. At the moment this problem is handled with some sort of lock. A temp file is created and then deleted at the end of the deletion flow. While that file exists the other thread (reordering or deletion depending on the user actions) awaits.

This is not an ideal solution and would like to change it. The potential solution must be also pretty fast (off course the current one is not a fast one) as the UI is updated thru a JSON call at the end of ordering.

In a later implementation we are thinking to use a queue of events but for the moment we are pretty stuck.

Any idea would be appreciated! Thank you, mosu'!

Edit: Other eventual consistency problems that we had were solved by using a Javascript data manager on the client side. Basically being optimist and tricking the user! :) I'm starting to believe this is the way to go here as well. But then how would I know when is the data changed in the file system?

mosu
  • 587
  • 2
  • 8
  • 20
  • You're using CQRS and an event centric architecture with eventual consistency for an image gallery? I'm sure you have your reasons, I'm really curious what they are. CQRS is not suited for everything. KISS still should be aplied. – Dennis Traub Apr 19 '13 at 11:54
  • Not really. The image gallery is just a piece of a vehicle management website. So far we didn't have the situation when some resources are used in such a concurrent context. Also, so far, CQRS worked pretty good for us. We are still learning and would like to learn from other users also! – mosu Apr 19 '13 at 15:20

2 Answers2

0

Here is one thought on this. What exactly you are reordering? Pictures? Based on, say, date. Why there is command for this? The result of this command going to be seen by everyone or just this particular user?

I can only guess, but it looks like you've got a presentation question here. There is no need to store pictures in some order on the write side, it's just a list of names and links to the file storage. What you should do is to store just a little field somewhere in the user settings or collection settings: Date ascending or Name descending. So you command Reorder should change only this little field. Then when you are loading the gallery this field should be read first and based on this you should load one or another view. Since the store is cheap nowadays, you can store differently sorted collections on the read side for every sort params you need.

To sum up, Delete command is changing the collection on the write side, but Reoder command is just user or collection setting. Hence, there is no concurrency here.

Update

Based on your comments and clarifications.

  1. Of course, you can and, probably, should restrict user actions only by one at the time. If time of deletion and reordering is reasonably short. It's always a question of type of user experience you are asked to achieve. Take a usual example of ordering system. After an order placed, user can almost immediately see it in the UI and the status will be something like InProcess. Most likely you won't let user to change the order in any way, which means you are not going to show any user controls like Cancel button(of course this is just an example). Hence, you can use this approach here.
  2. If 2 users can modify the same physical collection, you have no choice here - you are working with shared data and there should be kind of synchronization. For instance, if you are using sagas, there can be a couple of sagas: Collection reordering saga and Deletion saga - they can cooperate. Deletion process started first - collection aggregate was marked as deletion in progress and then right after this reordering saga started, it will attempt to start the reordering process, but since deletion saga is inprocess, it should wait for DeletedEvent and continue the process afterwards.The same if Reordering operation started first - the Deletion saga should wait until some event and continue after that event arrived.

Update

Ok, if we agreed not touch the file system itself, but the aggregate which represents the picture collection. The most important concurrency issues can be solved with optimistic concurrency approach - in the data storage a unique constraint, based on aggregate id and aggregate version, is usually used.

Here are the typical steps in the command handler:

This is the common sequence of steps a command handler follows:

  1. Validate the command on its own merits.
  2. Load the aggregate.
  3. Validate the command on the current state of the aggregate.
  4. Create a new event, apply the event to the aggregate in memory.
  5. Attempt to persist the aggregate. If there's a concurrency conflict during this step, either give up, or retry things from step 2.

Here is the link which helped me a lot some time ago: http://www.cqrs.nu/

Max
  • 601
  • 8
  • 21
  • I think I presented my problem in a slightly misleading way. Here are the steps that are causing trouble: User deletes 3 pictures, the Delete command is sent and at some point the physical pictures are deleted (in our solution deletion implies reordering). One second later the user resorts the pictures. The reorder command is sent but if the delete is not physically done nasty things happen. I like the idea of not reordering and only changing and index but this is a (big and used by other pieces of the monolit) legacy, system. I'm not sure that is a solution for us. Thank you for your answer! – mosu Apr 19 '13 at 19:27
  • Ok, I understand what Delete command does - it removes the file and change the Collection aggregate in the end. But what do you mean by Reordering? Just items order in the Collection aggregate or some physical order on the file system as well? – Max Apr 20 '13 at 07:02
  • The pictures are stored in the file system based on the article id, the pictures sizes and some mathematical algorithm so that the path of a picture can be created by just knowing the article id. The means there is a folder structure for each article. When the user is reordering (sorting the pictures) the paths change and so the pictures must be moved around. The sorting is also changed in the aggregate. Thank you! – mosu Apr 20 '13 at 13:37
0

Max suggestions are very welcomed and normally they apply.

It is hard sometimes to explain all the details of an implementation but there is a detail that should be mentioned: The way we store the pictures means that when reordered all pictures paths (and thus all links) change.

A colleague hat the very good idea of simply remove this part. That means that even if the order will change the path of the picture will remain the same. On the UI side there will be a mapping between the picture index in the display order and its path and this means there is no need to change the file system anymore, except when deleting.

As we want to be as permissive as possible with our users this is the best solution for us. I think, in general, it is also a good approach when there appears to be a concurrency issue. Can the concurrency be removed?

mosu
  • 587
  • 2
  • 8
  • 20