I have a service that distributes tasks to operators.
Inside a method I distribute many tasks in time inside a loop. I want to flush the task, the operator, and a DistributionLog. If I just had one domain to save I think I could do something like
Operator.withTransaction{ //...some code }
but I have at least 3 domains to save and to make it even worse, two of them have dependency on each other. The operator have a list of tasks.
I can't wait all the distribution to finish before an operator can get his tasks, so I have to force it to flush. To make it even harder, it's all inside a multitenantService.doWithTenant() (multitenant plugin)
You can get the session using the withSession method available in all domain classes and call to flush() on it.
Operator.withSession { session ->
// ...
session.flush()
}
If you want to do an explicit flush, you can get a reference to the hibernate session factory in your grails service like this:
def sessionFactory
You can then get the current hibernate session, and call flush on that:
sessionFactory.currentSession.flush()
You can force a flush with flush argument to the last call to save:
obj.save flush:true
See the documentation:
http://grails.github.io/grails-doc/2.2.5/ref/Domain%20Classes/save.html
The save method informs the persistence context that an instance should be saved or updated. The object will not be persisted immediately unless the flush argument is used:
b.save(flush: true)
Related
When I retrieve a domain instance via GORM, there is the possible danger of code modifying that instance/row. Especially because Grails automatically saves it even without calling .save() on the instance.
The only way I've ensured this before is making sure I call discard() on the instance in the past. Is there a better way?
This is for Grails 2.2.5
What version of Grails/GORM?
An option would be do this work in a #ReadOnly (or #Transactional(readOnly = true)) Transaction - an exception will be thrown if an write operation is attempted.
If you want to always require manual .save() calls, that's possible by changing the hibernate.flush.mode though even that has its risks. Using .discard() is your best bet in most cases. As Anton points out, you can use .isDirty() to find out if anything has changed, but that will not prevent the save from occurring.
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 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?
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.
In my application I have a static class (singleton) that needs to be initialized with some environmental variables that's used through out my layers, I'm calling it my applicationContext. That in turn has customer and user contexts.
As each job runs it modifies these customer and user contexts depending on the situation.
The problem I have is that when 2 jobs fires concurrently they might overwrite each others contexts, therefor I need to keep multiple user and customer contexts alive for each running job and I need to be able to pick the right context by somehow being able to see what the current job is.
Is it possible to somehow get information about the current executing quartz.net job?
I'm envisioning something like this where "currentQuartzJob.Name" is made up and is the part I'm missing:
public class MyContextImpl : IApplicationContext {
private Dictionary<string,subContexts> allCustomerContexts;
public string CurrentContext
{
get { return allCustomerContexts[currentQuartzJob.Name] };
}
}
edit:
I don't think it's possible to do what I wanted, that is to be able to get the executing job's name in a class that doesn't know about Quartz.Net.
What I really needed was a way to keep a different context for each job. I managed to do that by looking at the executing thread's ID as they seem to differ for each running job.
Try this:
public void Execute(IJobExecutionContext context)
{
var yourJobName = context.JobDetail.Key.Name;
}
Given your statement above: "The problem I have is that when 2 jobs fires concurrently they might overwrite each others contexts", you may want to reduce the complexity of your application by making sure that jobs do not fire concurrently. This can be achieved by implementing the IStatefulJob interface instead of the usual IJob interface: http://quartznet.sourceforge.net/tutorial/lesson_3.html
Alternatively if that is not an option you can query the Scheduler object for the currently executing jobs via the Ischeduler.GetCurrentlyExecutingJobs() method. This method returns an IList of those jobs but note the following remarks when using that method (from version 1.0.3 API):
This method is not cluster aware. That is, it will only return Jobs currently executing in this Scheduler instance, not across the entire cluster.
Note that the list returned is an 'instantaneous' snap-shot, and that as soon as it's returned, the true list of executing jobs may be different. Also please read the doc associated with JobExecutionContext- especially if you're using remoting.
I'm not entirely sure of what you're doing with your application, but I will say that the name of the currently executing job is definitely available during job execution.
Inside the IJob Execute() method:
// implementation in IJob
public void Execute(JobExecutionContext context)
{
// get name here
string jobName = context.JobDetail.Name;
}
Is that what you're looking for?