We have decoupled certain events by implementing listeners in exploded plugins (i.e. outside of the core application). Then we can build different implementations. Also, the listeners work must be outside any transaction, as it can take a long time (think connecting to the internet and waiting a long time, and if if fails, it must not rollback anything). The app is a webapp and api running on tomcat.
The problem is setChanged().
Here is a service:
class someService extends Observable {
}
Here is a plugin bootstrap:
SomeService someService
:
someService.addObserver(listenerService)
Here is the listener:
class ListenerService implements Observer {
#NotTransactional
void update(Observable o, Object arg) {
DomainObject domainObject (DomainObject) arg
// do somethign which takes a very log time
}
Here it is being called somewhere (e.g inside a method of someService, or elsewhere)
someService.setChanged()
someService.notifyObservers(someEvent)
I see a big problem here - if the setChanged is called my multiple requests, Each will set changed=true, but the first notifyObserver will set it to false, so when the second notifyObserer executes, it will see changed == false and return.
I see 2 possible solutions:
Put the observer on a domain object, which is not static.
hook into the afterUpdate domain event (not idea as we want to be outside the transaction, but we could start anther thread and do the work asynchronously)
Does anyone know if using the observer on the domain object (and calling setChanged and nofityObservers in some session) is a good solution?
Related
I need to execute some tasks after grails transaction ends. I'm not looking for afterCommit of Hibernate, instead of that, I need a method to be called after the transaction of the service ends.
Is there any way? I've read the documentation but I couldn't find anything, just normal events like afterUpdate or afterCommit.
Thanks!
You can add an event listener to the current session
sessionFactory.currentSession.addEventListener(...)
class MyListener extends BaseSessionEventListener {
#Override
void transactionCompletion(boolean successful) {
}
}
You just need to verify the transaction was successful via the parameter. Also understand that if there are multiple transactions in a single session the listener will be invoked for each one.
That really depends on what you're trying to do. The best bet is probably to call a #Transactional method on a service, and then when that returns, run the code that you need to happen after the transaction.
An alternative, if you just want to spin off some task to do something simple, you can use:
new java.util.Timer().runAfter(1000) { //time in milliseconds
//code to run here
}
This is just a shortcut to spin off a new thread and runs the closure body after (in the above example) 1 second... I believe the closure still has access to injected grails objects, but does not have access to the session. I'd double-check that though. I've used this in several places for sending notifications that needed to wait until after some processing inside a transaction ended.
We're running into a weird issue where objects are created in a first request, but they are not returned in a second request.
Let's assume we have two domain classes:
Class A {
static hasMany = [bs: B]
def afterUpdate() {
this.addToBs(new B(a: this))
this.save()
}
}
Class B {
static belongsTo = [a: A]
}
When a put is sent on an instance of A via PUT /as/<id>, update() is invoked in the RestfulController which is annotated with #Transactional.
What we can observe is, that every once in a while a follow-up request send by the API consumer after the response of the first request is returned, GET /bs does not return the new instance of B which should have been created in the first request and is also returned on further requests.
I'd expected that grails only sends the response to the API consumer once the transaction is committed, which would mean that the next request should see all changes from that transaction, shouldn't it?
What could be the reason for that behavior? Is the transaction committed after the grails app already sent the response to the API consumer? If so, is the reason the #Transactional around the update() which is turned on by default?
I know in this example the code in afterUpdate could probably also be put into beforeUpdate, but I just tried to to simplify the example as far as I could.
In my experience, code in afterUpdate() and the like are not included in the transaction. You'd have to create a transaction explicitly (and maybe a session too). See http://docs.grails.org/latest/ref/Domain%20Classes/withTransaction.html
I advise against GORM updates within afterUpdate() and friends because it leads to weird issues like this, and makes it difficult to unit test the domain models. If you delegate saving to a transactional service instead, not only would it just work, you'd also be able to confirm it with integration tests.
In my Grails apps, I keep my controllers really dumb:
Call a service
Return the service's output (possibly formatting it).
I keep all business logic in services because controllers are kind of a pain to test well. Here's an example:
#grails.transaction.Transactional
class SomeService {
def saveA(A a) {
// This method will run in a transaction.
a.addToBs(new B(a: this))
a.save()
}
}
And in the controller...
class SomeController {
def update() {
...
someService.save(a)
}
}
I add two annotations on the service method, after compiled, I found the method were compiled to a new class file, and I decompiled the generated class files and found the #CompileStatic were not work as wished.
Is is right or a bug of grails?
class FoobarService {
#grails.transaction.Transactional
#groovy.transform.CompileStatic
void foobar() {
....
}
}
The grails.transaction.Transactional annotation is a replacement for the traditional Spring org.springframework.transaction.annotation.Transactional annotation. It has the same attributes and features and works essentially the same, but it avoids an unfortunate side effect of using the Spring annotation.
The Spring annotation triggers the creation of a runtime proxy of the annotated class. Spring uses CGLIB to create a subclass of the target class (typically a Grails service) and an instance of the CGLIB proxy is registered as the Spring bean instead of registering a service instance directly. The proxy gets an instance of your service as a data variable.
Each method call is intercepted in the proxy, where it does whatever checks and/or setup is required based on the transaction settings, e.g. joining an existing transaction, creating a new one, throwing an exception because one isn't already running, etc. Once that's done, your real method is called.
But if you call another annotated method with different settings (e.g. the first method uses the default settings from #Transactional but the second should be run in a new separate transaction because it's annotated with #Transactional(propagation=REQUIRES_NEW)) then the second annotations settings will be ignored because you're "underneath" the proxy , inside the real instance of your service that the proxy is intercepting calls to. But it can't intercept direct calls like that.
The traditional workaround for this is to avoid direct calls and instead make the call on the proxy. You can't (at least not conveniently) inject the service bean into itself, but you can access the application context and access it that way. So the call that you would need in that situation would be something like
ctx.getBean('myService').otherMethod()
which works, but is pretty ugly.
The new Grails annotation works differently though. It triggers a reworking of the code via an AST transformation during compilation. A second method is created for each annotated method, and the code from the real method is moved inside there, in a GrailsTransactionTemplate that runs the code using the annotations settings. Once there, the code runs with the required transaction settings, but since every method is rewritten in this way, you don't have to worry about the proxy and where you're calling the methods from - there is no proxy.
Unfortunately there's a side effect that you're seeing - apparently the transformation happens in a way that isn't preserving the #CompileStatic annotation, so the code runs in dynamic mode. Sounds like a bug to me.
I have a service method to transfer funds to/from an external system.
it should create a transaction in our system first (so we have a transactionId)
Then we call the external system.
If the external system fails, we need to rollback the transaction, then write a new record in our payment audit log table, regardless of if the call failed or worked.
I cant figure out how to control the transaction in this case.
I understand services are transactional by default.
I assume I could create 3 methods (they are all 1 method now, which doesn't work as I have no control over what gets committed and what gets rolled back)
createPaymentTransaction()
sendToPaymentSystem()
createPaymentRecord()
I need to rollback 1 if 1 fails, and do nothing more.
I need to rollback 1 if 2 fails, but write 3.
I need to write 3 if 1 and 2 works.
I don't know how to annotate these, or how to structure a 4th request to manage the 3.
I'd go with something like this:
package com.myapp
import grails.transaction.Transactional
import org.springframework.transaction.annotation.Propagation
#Transactional
class MyService {
def createPaymentTransaction() {}
def sendToPaymentSystem() {}
#Transactional(propagation=Propagation.REQUIRES_NEW)
def createPaymentRecord() {}
def method4() {
try {
def transactionId = createPaymentTransaction()
sendToPaymentSystem(transactionId)
}
finally {
createPaymentRecord()
}
}
}
By annotating at the class level, we set the defaults for all methods, but can customize as needed, e.g. for createPaymentMethod.
So what will happen is that calling method4 will join an existing transaction, or start a new one if necessary. If there's a problem in either createPaymentTransaction or sendToPaymentSystem then the transaction will be rolled back, but the call to createPaymentRecord will happen because it's in the finally block, and it will run in a separate transaction so it isn't affected by a rollback in the main transaction, and a failure there doesn't affect the main transaction.
If you're not able to use the new grails.transaction.Transactional annotation, use the standard Spring org.springframework.transaction.annotation.Transactional annotation, but you need to make a small change. One of the motivations for the Grails annotation is to provide the same functionality as the Spring annotation, but avoid the problems with calling an annotated method from within the service. The Spring annotation triggers creation of a proxy at runtime which intercepts all calls, manages transactionality for the method, and then calls the real method in the service instance. But with the current code, the call to createPaymentRecord will bypass the proxy (the service instance is just calling itself) and there won't be a new transaction. The Grails annotation rewrites the bytecode to wrap each method in a transaction template which uses the applicable annotation settings (explicit or inferred from a class-scope annotation), so it works correctly internally and externally. If using the Spring annotation, you need to call the method on the proxy, which just involves accessing the Spring bean for this service. Add a dependency injection for the GrailsApplication as a field:
def grailsApplication
and then call createPaymentRecord via
grailsApplication.mainContext.myService.createPaymentRecord()
in the finally block.
By default all methods in a service are transactional, but you can change the behaviour on a method-by-method basis with annotations, e.g.
import grails.transaction.*
// By default all methods are transactional
#Transactional
class MyService {
#NotTransactional
def notTransactional() {
}
// inherits the class-level default
def transactional() {
}
}
See the Grails manual for more details about the transaction annotations.
If you need to manage transactions at a more fine-grained level than per-method, you can use the withTransaction domain class method to manage transactions programatically.
The question is how could I stop a method being called twice, where the first call has not "completed" because its handler is waiting for a url to load for example?
Here is the situation:
I have written a flash client which interfaces with a java server using a binary encrypted protocol (I would love to not have had to re-invent the whole client/server object communcation stack, but I had to encrypt the data in such a way that simple tools like tamper data and charles proxy could not pick them up if using SSL).
The API presents itself to flas as an actionscript swf file, and the API itself is a singleton.
the api exposes some simple methods, including:
login()
getBalance()
startGame()
endGame()
Each method will call my HttpCommunicator class.
HttpCommunicator.as (with error handling and stuff removed):
public class HttpCommunicator {
private var _externalHalder:function;
public function communicate(data:String, externalHandler:APIHandler):void {
// do encryption
// add message numbers etc to data.
this._externalHalder = externalHandler;
request.data = encrypt(addMessageNumers(data)));
loader.addEventListener(Event.COMPLETE, handleComplete);
loader.load(request);
}
private function handleComplete(event:Event):void {
var loader:URLLoader = URLLoader(event.target);
String data = decrypt(loader.data);
// check message numbers match etc.
_externalHandler(data);
}
The problem with this is I cant protect the same HttpCommunicator object from being called twice before the first has handled the complete event, unless:
I create a new HttpCommunicator object every single time I want to send a message. I also want to avoid creating a URLLoader each time, but this is not my code so will be more problematic to know how it behaves).
I can do something like syncronize on communicate. This would effectivly block, but this is better than currupting the data transmission. In theory, the Flash client should not call the same api function twice in a row, but I but it will happen.
I implement a queue of messages. However, this also needs syncronization around the push and pop methods, which I cant find how to do.
Will option 1. even work? If I have a singleton with a method say getBalance, and the getBalance method has:
// class is instantiated through a factory as a singleton
public class API{
var balanceCommunicator:HttpCommunicator = new HttpCommunicator(); // create one for all future calls.
public funciton getBalance(playerId:uint, hander:Fuction):Number {
balanceCommunicator.communicate(...); // this doesnt block
// do other stuff
}
Will the second call trounce the first calls communicator variable? i.e. will it behave as if its static, as there is onlyone copy of the API object?
If say there was a button on the GUI which had "update balance", and the user kept clicking on it, at the same time as say a URLLoader complete event hander being called which also cals the apis getBalance() function (i.e. flash being multithreaded).
Well, first off, with the exception of the networking APIs, Flash is not multithreaded. All ActionScript runs in the same one thread.
You could fairly easily create a semaphore-like system where each call to communicate passed in a "key" as well as the arguments you already specified. That "key" would just be a string that represented the type of call you're doing (getBalance, login, etc). The "key" would be a property in a generic object (Object or Dictionary) and would reference an array (it would have to be created if it didn't exist).
If the array was empty then the call would happen as normal. If not then the information about the call would be placed into an object and pushed into the array. Your complete handler would then have to just check, after it finished a call, if there were more requests in the queue and if so dequeue one of them and run that request.
One thing about this system would be that it would still allow different types of requests to happen in parallel - but you would have to have a new URLLoader per request (which is perfectly reasonable as long as you clean it up after each request is done).