Handling transaction rollbacks with Grails persistence events

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Handling transaction rollbacks with Grails persistence events

Sitati Kituyi
Hi all,

I've got a scenario where I want to detect all CRUD operations on some domains in my grails app (we're on 2.4.3), and automatically invoke some business logic. After researching my options, I've found and tested two general approaches that both work to an extent:
- Using afterInsert, afterUpdate and afterDelete in the relevant domains
- Using an AbstractPersistenceEventListener, filtering for the relevant classes in the onPersistenceEvent method

The problem I now face is that in transactional blocks, both these approaches result in the event handler being invoked immediately after a domain.save() is invoked. If a RuntimeException occurs later in the transaction, the transaction is rolled back and the domain is not persisted, but this business logic will have already been invoked. I'm testing with code that looks like this:

MyDomain.withNewTransaction {
   
new MyDomain(name:'Jeopardy').save() // << Event is thrown here
    sleep
(20000) // << I added this just so that I could assert through the front-end that the business logic has indeed been invoked before the transaction ended
   
throw new Exception("but it fails!") // << this causes rollback, so the MyDomain instance is not saved
}



The ideal solution I'm hoping to find is a setup that allows for a 1:1 match between the invocation of the handler and db level inserts: whether in a transactional context or not, only raise the event when an insert/update is actually committed at database level. Failing this, I'd settle for some way to detect these rollbacks and call some handler, knowing which entities were affected by the rollback (in other words, an 'undo' method for the business logic that was invoked).

Any ideas? Thanks!

--
You received this message because you are subscribed to the Google Groups "Grails Dev Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/grails-dev-discuss/ca5b8426-faca-4bf4-a821-3759fe6eebee%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Handling transaction rollbacks with Grails persistence events

Robert Oschwald
Maybe the audit-logging plugin is an option, with „handlersOnly = true“ setting if needed.

Robert






Am 04.02.2016 um 14:42 schrieb Sitati Kituyi <[hidden email]>:

Hi all,

I've got a scenario where I want to detect all CRUD operations on some domains in my grails app (we're on 2.4.3), and automatically invoke some business logic. After researching my options, I've found and tested two general approaches that both work to an extent:
- Using afterInsert, afterUpdate and afterDelete in the relevant domains
- Using an AbstractPersistenceEventListener, filtering for the relevant classes in the onPersistenceEvent method

The problem I now face is that in transactional blocks, both these approaches result in the event handler being invoked immediately after a domain.save() is invoked. If a RuntimeException occurs later in the transaction, the transaction is rolled back and the domain is not persisted, but this business logic will have already been invoked. I'm testing with code that looks like this:


MyDomain.withNewTransaction {
   
new MyDomain(name:'Jeopardy').save() // << Event is thrown here
    sleep
(20000) // << I added this just so that I could assert through the front-end that the business logic has indeed been invoked before the transaction ended
   
throw new Exception("but it fails!") // << this causes rollback, so the MyDomain instance is not saved
}



The ideal solution I'm hoping to find is a setup that allows for a 1:1 match between the invocation of the handler and db level inserts: whether in a transactional context or not, only raise the event when an insert/update is actually committed at database level. Failing this, I'd settle for some way to detect these rollbacks and call some handler, knowing which entities were affected by the rollback (in other words, an 'undo' method for the business logic that was invoked).

Any ideas? Thanks!

--
You received this message because you are subscribed to the Google Groups "Grails Dev Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/grails-dev-discuss/ca5b8426-faca-4bf4-a821-3759fe6eebee%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Grails Dev Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/grails-dev-discuss/CB93C0F3-CE8E-4157-B9E2-A21DC681D5BB%40gmail.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

RE: Handling transaction rollbacks with Grails persistence events

asachdeva
In reply to this post by Sitati Kituyi

If your business logic involves updating Database, then it should be fine. But if it involves archiving files, sending mails or raising audit events etc then either you need to have an explicit rollback(for example files can be un-archived in case of rollback, and a followup audit event can be raised) for the business logic, or you need to queue the tasks in afterUpdate (and related functions) and invoke them at commit. For example mails should be sent only after all DB operations has been committed.

 

It depends on what is the business logic that gets executed at each db commit. If anybody can suggest a better approach please do because AFAIK business logic executed prior to commit needs to be manually handled in case of rollback.

 

Regards

Arvind Sachdeva.

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Sitati Kituyi
Sent: 04 February 2016 19:13
To: Grails Dev Discuss
Subject: Handling transaction rollbacks with Grails persistence events

 

Hi all,

 

I've got a scenario where I want to detect all CRUD operations on some domains in my grails app (we're on 2.4.3), and automatically invoke some business logic. After researching my options, I've found and tested two general approaches that both work to an extent:

- Using afterInsert, afterUpdate and afterDelete in the relevant domains

- Using an AbstractPersistenceEventListener, filtering for the relevant classes in the onPersistenceEvent method

 

The problem I now face is that in transactional blocks, both these approaches result in the event handler being invoked immediately after a domain.save() is invoked. If a RuntimeException occurs later in the transaction, the transaction is rolled back and the domain is not persisted, but this business logic will have already been invoked. I'm testing with code that looks like this:

MyDomain.withNewTransaction {
   
new MyDomain(name:'Jeopardy').save() // << Event is thrown here
    sleep
(20000) // << I added this just so that I could assert through the front-end that the business logic has indeed been invoked before the transaction ended
   
throw new Exception("but it fails!") // << this causes rollback, so the MyDomain instance is not saved
}

 

The ideal solution I'm hoping to find is a setup that allows for a 1:1 match between the invocation of the handler and db level inserts: whether in a transactional context or not, only raise the event when an insert/update is actually committed at database level. Failing this, I'd settle for some way to detect these rollbacks and call some handler, knowing which entities were affected by the rollback (in other words, an 'undo' method for the business logic that was invoked).

 

Any ideas? Thanks!

--
You received this message because you are subscribed to the Google Groups "Grails Dev Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/grails-dev-discuss/ca5b8426-faca-4bf4-a821-3759fe6eebee%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Grails Dev Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/grails-dev-discuss/MA1PR01MB0582955BBFADF635727BA003C6D10%40MA1PR01MB0582.INDPRD01.PROD.OUTLOOK.COM.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Handling transaction rollbacks with Grails persistence events

Sitati Kituyi
Thanks for the quick replies Robert & Arvind.

I'll set up a quick test app using the audit-logging plugin to see if it behaves as desired with the code snippet I gave above. If it does, I'll have a look at source, maybe I can find something in their approach that shows how they handle this.

Arvind, I agree with the rules you described. Our business logic is actually not db related, but it's a safe operation that can be rolled back, similar to your example of un-archiving files. What I don't know is how to detect transaction rollback in order to run this 'undo' operation. Is there an event I can listen to for that? Alternatively, you also suggested queueing things, and only executing when the transaction is committed. Again, how do I detect this, is there an event from which I can get the list of domains that were committed?

I'm ok with either approach (queue and execute on "transactionSuccess" event, or execute immediately and roll back on "transactionRollback" event), but I can't find any docs about either of those events being available.

On Thursday, February 4, 2016 at 5:20:36 PM UTC+3, Arvind Sachdeva wrote:

If your business logic involves updating Database, then it should be fine. But if it involves archiving files, sending mails or raising audit events etc then either you need to have an explicit rollback(for example files can be un-archived in case of rollback, and a followup audit event can be raised) for the business logic, or you need to queue the tasks in afterUpdate (and related functions) and invoke them at commit. For example mails should be sent only after all DB operations has been committed.

 

It depends on what is the business logic that gets executed at each db commit. If anybody can suggest a better approach please do because AFAIK business logic executed prior to commit needs to be manually handled in case of rollback.

 

Regards

Arvind Sachdeva.

 

From: <a href="javascript:" target="_blank" gdf-obfuscated-mailto="2uMzKJ2mBwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">grails-de...@googlegroups.com [mailto:<a href="javascript:" target="_blank" gdf-obfuscated-mailto="2uMzKJ2mBwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">grails-de...@googlegroups.com] On Behalf Of Sitati Kituyi
Sent: 04 February 2016 19:13
To: Grails Dev Discuss
Subject: Handling transaction rollbacks with Grails persistence events

 

Hi all,

 

I've got a scenario where I want to detect all CRUD operations on some domains in my grails app (we're on 2.4.3), and automatically invoke some business logic. After researching my options, I've found and tested two general approaches that both work to an extent:

- Using afterInsert, afterUpdate and afterDelete in the relevant domains

- Using an AbstractPersistenceEventListener, filtering for the relevant classes in the onPersistenceEvent method

 

The problem I now face is that in transactional blocks, both these approaches result in the event handler being invoked immediately after a domain.save() is invoked. If a RuntimeException occurs later in the transaction, the transaction is rolled back and the domain is not persisted, but this business logic will have already been invoked. I'm testing with code that looks like this:

MyDomain.withNewTransaction {
   
new MyDomain(name:'Jeopardy').save() // << Event is thrown here
    sleep
(20000) // << I added this just so that I could assert through the front-end that the business logic has indeed been invoked before the transaction ended
   
throw new Exception("but it fails!") // << this causes rollback, so the MyDomain instance is not saved
}

 

The ideal solution I'm hoping to find is a setup that allows for a 1:1 match between the invocation of the handler and db level inserts: whether in a transactional context or not, only raise the event when an insert/update is actually committed at database level. Failing this, I'd settle for some way to detect these rollbacks and call some handler, knowing which entities were affected by the rollback (in other words, an 'undo' method for the business logic that was invoked).

 

Any ideas? Thanks!

--
You received this message because you are subscribed to the Google Groups "Grails Dev Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="2uMzKJ2mBwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">grails-dev-discuss+unsubscribe@....
To post to this group, send email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="2uMzKJ2mBwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;"> grails-d...@googlegroups.com.
To view this discussion on the web visit <a href="https://groups.google.com/d/msgid/grails-dev-discuss/ca5b8426-faca-4bf4-a821-3759fe6eebee%40googlegroups.com?utm_medium=email&amp;utm_source=footer" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/msgid/grails-dev-discuss/ca5b8426-faca-4bf4-a821-3759fe6eebee%40googlegroups.com?utm_medium\75email\46utm_source\75footer&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/msgid/grails-dev-discuss/ca5b8426-faca-4bf4-a821-3759fe6eebee%40googlegroups.com?utm_medium\75email\46utm_source\75footer&#39;;return true;"> https://groups.google.com/d/msgid/grails-dev-discuss/ca5b8426-faca-4bf4-a821-3759fe6eebee%40googlegroups.com.
For more options, visit <a href="https://groups.google.com/d/optout" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Grails Dev Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/grails-dev-discuss/a92c0729-fcdb-4d58-91d5-79f28414a594%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Handling transaction rollbacks with Grails persistence events

Sitati Kituyi
In reply to this post by Sitati Kituyi
Had a look at the audit-logging plugin source, it's using the same AbstractPersitenceEventListener approach that I've already tested: https://github.com/robertoschwald/grails-audit-logging-plugin/blob/1.x_maintenance/grails-audit-logging-plugin/src/groovy/org/codehaus/groovy/grails/plugins/orm/auditable/AuditLogListener.groovy

This will not work - the event is thrown on save() instead of at the transaction boundary.

There are open issues in the repo about the plugin's behaviour on rolled-back transactions: https://github.com/robertoschwald/grails-audit-logging-plugin/issues/88

Unfortunately that plugin won't help here.

To simplify the question (for anyone skimming through this): is there a way to detect transaction commit or rollback as an event?

On Thursday, February 4, 2016 at 4:42:59 PM UTC+3, Sitati Kituyi wrote:
Hi all,

I've got a scenario where I want to detect all CRUD operations on some domains in my grails app (we're on 2.4.3), and automatically invoke some business logic. After researching my options, I've found and tested two general approaches that both work to an extent:
- Using afterInsert, afterUpdate and afterDelete in the relevant domains
- Using an AbstractPersistenceEventListener, filtering for the relevant classes in the onPersistenceEvent method

The problem I now face is that in transactional blocks, both these approaches result in the event handler being invoked immediately after a domain.save() is invoked. If a RuntimeException occurs later in the transaction, the transaction is rolled back and the domain is not persisted, but this business logic will have already been invoked. I'm testing with code that looks like this:

MyDomain.withNewTransaction {
   
new MyDomain(name:'Jeopardy').save() // << Event is thrown here
    sleep
(20000) // << I added this just so that I could assert through the front-end that the business logic has indeed been invoked before the transaction ended
   
throw new Exception("but it fails!") // << this causes rollback, so the MyDomain instance is not saved
}



The ideal solution I'm hoping to find is a setup that allows for a 1:1 match between the invocation of the handler and db level inserts: whether in a transactional context or not, only raise the event when an insert/update is actually committed at database level. Failing this, I'd settle for some way to detect these rollbacks and call some handler, knowing which entities were affected by the rollback (in other words, an 'undo' method for the business logic that was invoked).

Any ideas? Thanks!

--
You received this message because you are subscribed to the Google Groups "Grails Dev Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/grails-dev-discuss/206a425f-5b0c-479f-8373-e5134ea02cc7%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Handling transaction rollbacks with Grails persistence events

Robert Oschwald
With Hibernate, an EmptyInterceptor would work, as you got access to the Transaction in afterTransactionCompletion(), but I do not know a GORM way to get the same thing in an ORM agnostic way.



> Am 04.02.2016 um 15:57 schrieb Sitati Kituyi <[hidden email]>:
>
> Had a look at the audit-logging plugin source, it's using the same AbstractPersitenceEventListener approach that I've already tested: https://github.com/robertoschwald/grails-audit-logging-plugin/blob/1.x_maintenance/grails-audit-logging-plugin/src/groovy/org/codehaus/groovy/grails/plugins/orm/auditable/AuditLogListener.groovy
>
> This will not work - the event is thrown on save() instead of at the transaction boundary.
>
> There are open issues in the repo about the plugin's behaviour on rolled-back transactions: https://github.com/robertoschwald/grails-audit-logging-plugin/issues/88
>
> Unfortunately that plugin won't help here.
>
> To simplify the question (for anyone skimming through this): is there a way to detect transaction commit or rollback as an event?
>
> On Thursday, February 4, 2016 at 4:42:59 PM UTC+3, Sitati Kituyi wrote:
> Hi all,
>
> I've got a scenario where I want to detect all CRUD operations on some domains in my grails app (we're on 2.4.3), and automatically invoke some business logic. After researching my options, I've found and tested two general approaches that both work to an extent:
> - Using afterInsert, afterUpdate and afterDelete in the relevant domains
> - Using an AbstractPersistenceEventListener, filtering for the relevant classes in the onPersistenceEvent method
>
> The problem I now face is that in transactional blocks, both these approaches result in the event handler being invoked immediately after a domain.save() is invoked. If a RuntimeException occurs later in the transaction, the transaction is rolled back and the domain is not persisted, but this business logic will have already been invoked. I'm testing with code that looks like this:
>
>
> MyDomain.withNewTransaction {
>     new MyDomain(name:'Jeopardy').save() // << Event is thrown here
>     sleep(20000) // << I added this just so that I could assert through the front-end that the business logic has indeed been invoked before the transaction ended
>     throw new Exception("but it fails!") // << this causes rollback, so the MyDomain instance is not saved
> }
>
>
>
> The ideal solution I'm hoping to find is a setup that allows for a 1:1 match between the invocation of the handler and db level inserts: whether in a transactional context or not, only raise the event when an insert/update is actually committed at database level. Failing this, I'd settle for some way to detect these rollbacks and call some handler, knowing which entities were affected by the rollback (in other words, an 'undo' method for the business logic that was invoked).
>
> Any ideas? Thanks!
>
> --
> You received this message because you are subscribed to the Google Groups "Grails Dev Discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
> To post to this group, send email to [hidden email].
> To view this discussion on the web visit https://groups.google.com/d/msgid/grails-dev-discuss/206a425f-5b0c-479f-8373-e5134ea02cc7%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Grails Dev Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/grails-dev-discuss/3A560692-31B7-480F-A2AB-CCAD0FD4CA5B%40gmail.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Handling transaction rollbacks with Grails persistence events

Sitati Kituyi
This looks a promising direction, thanks Robert.

I can see from the Transaction javadoc that we'll be able to tell whether the transaction rolled back or was successful, but is there an API that lets me see the affected domain instances in the event of a rollback/commit?

On Thursday, February 4, 2016 at 6:17:47 PM UTC+3, Robert Oschwald wrote:
With Hibernate, an EmptyInterceptor would work, as you got access to the Transaction in afterTransactionCompletion(), but I do not know a GORM way to get the same thing in an ORM agnostic way.



> Am 04.02.2016 um 15:57 schrieb Sitati Kituyi <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="YYcK1bupBwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">sitati...@...>:
>
> Had a look at the audit-logging plugin source, it's using the same AbstractPersitenceEventListener approach that I've already tested: <a href="https://github.com/robertoschwald/grails-audit-logging-plugin/blob/1.x_maintenance/grails-audit-logging-plugin/src/groovy/org/codehaus/groovy/grails/plugins/orm/auditable/AuditLogListener.groovy" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\75https%3A%2F%2Fgithub.com%2Frobertoschwald%2Fgrails-audit-logging-plugin%2Fblob%2F1.x_maintenance%2Fgrails-audit-logging-plugin%2Fsrc%2Fgroovy%2Forg%2Fcodehaus%2Fgroovy%2Fgrails%2Fplugins%2Form%2Fauditable%2FAuditLogListener.groovy\46sa\75D\46sntz\0751\46usg\75AFQjCNGHV_-P1B37TbwH-MoDlOaAGDHH2w&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\75https%3A%2F%2Fgithub.com%2Frobertoschwald%2Fgrails-audit-logging-plugin%2Fblob%2F1.x_maintenance%2Fgrails-audit-logging-plugin%2Fsrc%2Fgroovy%2Forg%2Fcodehaus%2Fgroovy%2Fgrails%2Fplugins%2Form%2Fauditable%2FAuditLogListener.groovy\46sa\75D\46sntz\0751\46usg\75AFQjCNGHV_-P1B37TbwH-MoDlOaAGDHH2w&#39;;return true;">https://github.com/robertoschwald/grails-audit-logging-plugin/blob/1.x_maintenance/grails-audit-logging-plugin/src/groovy/org/codehaus/groovy/grails/plugins/orm/auditable/AuditLogListener.groovy
>
> This will not work - the event is thrown on save() instead of at the transaction boundary.
>
> There are open issues in the repo about the plugin's behaviour on rolled-back transactions: <a href="https://github.com/robertoschwald/grails-audit-logging-plugin/issues/88" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\75https%3A%2F%2Fgithub.com%2Frobertoschwald%2Fgrails-audit-logging-plugin%2Fissues%2F88\46sa\75D\46sntz\0751\46usg\75AFQjCNESUWN-i9qT7NtXMf1KG8bUMmIokA&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\75https%3A%2F%2Fgithub.com%2Frobertoschwald%2Fgrails-audit-logging-plugin%2Fissues%2F88\46sa\75D\46sntz\0751\46usg\75AFQjCNESUWN-i9qT7NtXMf1KG8bUMmIokA&#39;;return true;">https://github.com/robertoschwald/grails-audit-logging-plugin/issues/88
>
> Unfortunately that plugin won't help here.
>
> To simplify the question (for anyone skimming through this): is there a way to detect transaction commit or rollback as an event?
>
> On Thursday, February 4, 2016 at 4:42:59 PM UTC+3, Sitati Kituyi wrote:
> Hi all,
>
> I've got a scenario where I want to detect all CRUD operations on some domains in my grails app (we're on 2.4.3), and automatically invoke some business logic. After researching my options, I've found and tested two general approaches that both work to an extent:
> - Using afterInsert, afterUpdate and afterDelete in the relevant domains
> - Using an AbstractPersistenceEventListener, filtering for the relevant classes in the onPersistenceEvent method
>
> The problem I now face is that in transactional blocks, both these approaches result in the event handler being invoked immediately after a domain.save() is invoked. If a RuntimeException occurs later in the transaction, the transaction is rolled back and the domain is not persisted, but this business logic will have already been invoked. I'm testing with code that looks like this:
>
>
> MyDomain.withNewTransaction {
>     new MyDomain(name:'Jeopardy').save() // << Event is thrown here
>     sleep(20000) // << I added this just so that I could assert through the front-end that the business logic has indeed been invoked before the transaction ended
>     throw new Exception("but it fails!") // << this causes rollback, so the MyDomain instance is not saved
> }
>
>
>
> The ideal solution I'm hoping to find is a setup that allows for a 1:1 match between the invocation of the handler and db level inserts: whether in a transactional context or not, only raise the event when an insert/update is actually committed at database level. Failing this, I'd settle for some way to detect these rollbacks and call some handler, knowing which entities were affected by the rollback (in other words, an 'undo' method for the business logic that was invoked).
>
> Any ideas? Thanks!
>
> --
> You received this message because you are subscribed to the Google Groups "Grails Dev Discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="YYcK1bupBwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">grails-dev-discuss+unsubscribe@....
> To post to this group, send email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="YYcK1bupBwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">grails-de...@googlegroups.com.
> To view this discussion on the web visit <a href="https://groups.google.com/d/msgid/grails-dev-discuss/206a425f-5b0c-479f-8373-e5134ea02cc7%40googlegroups.com" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/msgid/grails-dev-discuss/206a425f-5b0c-479f-8373-e5134ea02cc7%40googlegroups.com&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/msgid/grails-dev-discuss/206a425f-5b0c-479f-8373-e5134ea02cc7%40googlegroups.com&#39;;return true;">https://groups.google.com/d/msgid/grails-dev-discuss/206a425f-5b0c-479f-8373-e5134ea02cc7%40googlegroups.com.
> For more options, visit <a href="https://groups.google.com/d/optout" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Grails Dev Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/grails-dev-discuss/c6344ca9-b562-456f-aa53-d7fe457f5146%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Handling transaction rollbacks with Grails persistence events

Jimmy Mbiyu
In reply to this post by Sitati Kituyi
Hello,

You can achieve your goal by using Hibernate Events as detailed here https://grails.github.io/grails-doc/latest/guide/GORM.html#eventsAutoTimestamping

In light of this Hibernate ticket, https://hibernate.atlassian.net/browse/HHH-1582, make sure you use Hibernate 4. You can install the Hibernate 4 plugin as detailed in the Grails 2.4.3 release notes if you are not already using Hibernate 4 - https://grails.org/wiki/2.4.3%20Release%20Notes. The Events API has changed so the classes/interfaces to look out for are in the org.hibernate.event.spi package.

Regards,
Ndung'u.  

On Thursday, 4 February 2016 16:42:59 UTC+3, Sitati Kituyi wrote:
Hi all,

I've got a scenario where I want to detect all CRUD operations on some domains in my grails app (we're on 2.4.3), and automatically invoke some business logic. After researching my options, I've found and tested two general approaches that both work to an extent:
- Using afterInsert, afterUpdate and afterDelete in the relevant domains
- Using an AbstractPersistenceEventListener, filtering for the relevant classes in the onPersistenceEvent method

The problem I now face is that in transactional blocks, both these approaches result in the event handler being invoked immediately after a domain.save() is invoked. If a RuntimeException occurs later in the transaction, the transaction is rolled back and the domain is not persisted, but this business logic will have already been invoked. I'm testing with code that looks like this:

MyDomain.withNewTransaction {
   
new MyDomain(name:'Jeopardy').save() // << Event is thrown here
    sleep
(20000) // << I added this just so that I could assert through the front-end that the business logic has indeed been invoked before the transaction ended
   
throw new Exception("but it fails!") // << this causes rollback, so the MyDomain instance is not saved
}



The ideal solution I'm hoping to find is a setup that allows for a 1:1 match between the invocation of the handler and db level inserts: whether in a transactional context or not, only raise the event when an insert/update is actually committed at database level. Failing this, I'd settle for some way to detect these rollbacks and call some handler, knowing which entities were affected by the rollback (in other words, an 'undo' method for the business logic that was invoked).

Any ideas? Thanks!

--
You received this message because you are subscribed to the Google Groups "Grails Dev Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/grails-dev-discuss/eda6d2ff-a9c8-42f5-8069-d29cb74c1cdb%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.