tl:dr; This is a bit involved of a problem, any advice is welcome, appreciate reading in advance :)
My coworkers and I have been struggling a bit with an odd behavior in our batch processing application. We recently upgraded it from Grails 1.3.7 to 2.1
The stacktrace is showing the following error:
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException:
Cannot insert the value NULL into column 'date_created',
table 'dev.dbo.notification_log'; column does not allow nulls. INSERT fails.
...
[quartzScheduler_Worker-1] [||] ERROR hibernate.AssertionFailure - an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
org.hibernate.AssertionFailure: null id in com.virtuwell.domain.NotificationLog entry (don't flush the Session after an exception occurs)
at org.quartz.core.QuartzScheduler.notifyJobListenersWasExecuted(QuartzScheduler.java:1891)
at org.quartz.core.JobRunShell.notifyJobListenersComplete(JobRunShell.java:352)
at org.quartz.core.JobRunShell.run(JobRunShell.java:223)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:546)
[quartzScheduler_Worker-1] [||] ERROR listeners.SessionBinderJobListener - Cannot flush Hibernate Sesssion, error will be ignored
org.hibernate.AssertionFailure: null id in com.virtuwell.domain.NotificationLog entry (don't flush the Session after an exception occurs)
at org.quartz.core.QuartzScheduler.notifyJobListenersWasExecuted(QuartzScheduler.java:1891)
at org.quartz.core.JobRunShell.notifyJobListenersComplete(JobRunShell.java:352)
at org.quartz.core.JobRunShell.run(JobRunShell.java:223)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:546)
Here is the code of that particular Domain Object (NotificationLog)
class NotificationLog implements Serializable{
Date dateCreated
Notification notification
NotificationDeliveryState deliveryState
String message
static mapping = {
message type: 'text'
}
}
What's strange, however, is this error doesn't occur EVERY time that domain object is persisted, and we only have one place in the code that object is ever persisted, shown below:
class NotificationLogService {
boolean transactional = true
def logNotification(Notification notification, message, deliveryState) {
def notificationLog = new NotificationLog(
notification: notification,
deliveryState: deliveryState,
message:message
)
try{
notificationLog.save(failOnError:true)
} catch (Exception e) { // Failure to save a notificationLog should not rollback the calling transaction
log.error "NotificationLog State:[$deliveryState] for notification:${notification?.id} did not save. Errors: ${notificationLog?.errors}, Message:$message", e
}
}
}
We've found a 'hack' of a workaround in the below SO question where we are no longer periodically seeing the error in the logs, by adding this to the Domain Object
static mapping = {
autoTimestamp true
}
But this isn't the only domain we're seeing with the SAME periodic failure to save (thus, I need to add the mapping to other domains), and if this truly is necessary for dateCreated
to function properly in Grails 2.1, I need to add it to a LOT more domains!
Worse, I can't reproduce it in a Unit or Integration test, its only happening on our running Dev and QA instances.
So, 2 Questions:
Does anyone know why this error might be periodically occurring?
If not, is there a way I can globally add this
autoTimestamp true
mapping to ALL of my project's domain objects (I've been unable to find documentation for how to add it at all, other than to set it tofalse
)
Relevant SO Question: dateCreated, lastUpdated fields in Grails 2.0
Relevant Grails Maillist discussion http://grails.1312388.n4.nabble.com/dateCreated-lastUpdated-in-Grails-2-0-td4337894.html
Relevant Grails docs on autoTimestamp GORM properties http://grails.org/doc/latest/guide/GORM.html#eventsAutoTimestamping
Have you tried to manually insert the date when creating a new NotificationLog? Like this:
}