Note that there are some explanatory texts on larger screens.

plurals
  1. POSending events at the end of a transaction
    primarykey
    data
    text
    <p>I have an interface for a Service object that looks something like the following (simplified for brevity):</p> <pre><code>public interface ItemService { public Item getItemById(String itemId, int version); public void create(Item item, User user); public void update(Item item, User user); public void delete(Item item, User user); } </code></pre> <p><code>ItemService</code> a single implementation, and is wired up as a Spring bean. It gets used by the UI portion of our project, and by the code that handles Ajax requests, to create and modify <code>Item</code> objects in our data store.</p> <p>Under the hood each method sends out a series of Events when it gets called. The Events are received by other modules to do things like keep Lucene indexes up to date, or to send messages to administrators to let them know something has changed. Each method call constitutes a single transaction in Spring (using <code>org.springframework.orm.hibernate3.HibernateTransactionManager</code> and <code>org.springframework.transaction.interceptor.TransactionProxyFactoryBean</code>). </p> <p>Recently there has been a need to <strong>compose</strong> a number of method calls together in a single transaction. Sometimes with more than one Service. For example, we might want to do something like:</p> <pre><code>*Begin transaction* Get Items created by User Bill using ItemService for each Item in Items Update field on Item Link Item to User Bill with LinkService Update Item using ItemService *Finish transaction* </code></pre> <p>We've done this by creating another Service which allows you to compose calls from Services in a single method in the parent service. Lets call it <code>ComposingService</code>. <code>ComposingService</code>, as with all the others, is also managed by Spring, and as transactions are reentrant, this should all work..</p> <p>However, there is a problem: if any of those operations within the transaction fail, causing the transaction to roll back <strong>we do not want to send out any Events whatsoever</strong>. </p> <p>As it stands, if the transaction fails halfway through, half the Events will be sent by <code>ItemService</code> before the transaction rolls back, meaning that some modules will receive a bunch of Events for things that haven't happened. </p> <p>We are trying to find some way of fixing this, but we've been unable to think of anything elegant. The best we've come up with so far, is something like this (and it's ugly):</p> <pre><code>public interface ItemService { public Item getItemById(String itemId, int version); public void create(Item item, User user, List&lt;Event&gt; events); public void update(Item item, User user, List&lt;Event&gt; events); public void delete(Item item, User user, List&lt;Event&gt; events); } </code></pre> <p>In this modified ItemService, instead of the Events being sent right away, they are added to the List of Events passed in as an argument. The list is maintained by <code>ComposingService</code>, and the Events get sent by <code>ComposingService</code> once all the calls to <code>ItemService</code> and other services have exited successfully. </p> <p>Obviously, the problem is that we've changed the contract on ItemService in an ugly manner. Calling classes, even if they are services, should not have to worry about managing Events. But I've been unable to think of a way around this, hence this question. </p> <p>This looks like the kind of problem that has probably been solved before. Has anyone had a problem that looks similar, and if so, how did you resolve it?</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload