两个星期后,出现了一个疯狂的问题! 它只出现在生产中(不是开发,集成,预生产模式)和下班后....
症状:一旦发生“某事”,用户就无法注册了。经过数天和数天的调查,我不知道如何重现这个问题。 目前,我们有一个丑陋的解决方法来重启tomcat实例,但这是非常丑陋。
有关信息,两次发货之间的差异与报名流程无关。
我认为这是相关的:
域名:
class UserAccount implements Serializable {
static transients = ['tokenLogin']
String email
String pwd
Date creationDate = new Date()
String tokenLogin
//[skip] dozen of other attributes
static constraints = {
email(matches:EmailRegexp,blank:false)
pwd(blank:false)
tokenLogin(editable:false)
}
public void setEmail(String email) {
this.email = email
authId = authenticationChannel.getUsername(email)
// We must recalculate token login
this.tokenLogin = generateTokenLogin(email, creationDate, pwd)
}
public void setPwd(String pwd) {
this.pwd = pwd
// We must recalculate token login
this.tokenLogin = generateTokenLogin(email, creationDate, pwd)
}
public static String generateTokenLogin(String email, Date creationDate, String pwd) {
// work well
// even tested when return null or with NPE in it and does not produce the same log
generated = // work with MessageDigest, MD5, salt, etc. (not disclosed, because we are currently under security audit)
return generated;
}
}
控制器:
def saveAccount = {
def user = new UserAccount(email: params.email?.trim(), pwd: params.pwd) // More parameters, but here what is relevant
user.validate()
if(user.hasErrors()) log.info("${user.errors}") // added since the issue appears
// Other verification (unicity, clear password verification, etc.)
// Password encryption
// user.save()
}
输出日志:
2013-06-03 15:37:32,165 [TP-Processor46] INFO controller.UserAccountController - org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'domain.UserAccount' on field 'pwd': rejected value [foobar]; codes [methodInvocation.domain.UserAccount.pwd,methodInvocation.pwd,methodInvocation.java.lang.String,methodInvocation]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [domain.UserAccount.pwd,pwd]; arguments []; default message [pwd]]; default message [Property 'pwd' threw exception; nested exception is java.lang.NullPointerException]
问题:
pwd
或email
字段中看到了此输出,而从未见过其他字段。MethodInvocationException
捕获异常时抛出BeanWrapperImpl.setPropertyValue
信息:
在start.sh
(tomcat选项)
JAVA_OPTS="-Dapp=prod -Xms1024m -Xmx1024m -XX:MaxPermSize=256m \
-Dfile.encoding=UTF-8 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC \
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled \
-XX:+HeapDumpOnOutOfMemoryError \
-Xloggc:/path/to/gc.log"
编辑:
我们更改并编译spring-context.jar
以便能够看到StackTrace。我们得到这个:
org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessException details (1) are:
PropertyAccessException 1:
org.springframework.beans.MethodInvocationException: Property 'pwd' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1127)
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:900)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:76)
at org.springframework.validation.DataBinder.applyPropertyValues(DataBinder.java:673)
at org.springframework.validation.DataBinder.doBind(DataBinder.java:569)
at org.springframework.web.bind.WebDataBinder.doBind(WebDataBinder.java:191)
[snip]
Caused by: java.lang.NullPointerException
at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.checkCall(PojoMetaClassSite.java:54)
at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:42)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
at domain.UserAccount.generateTokenLogin(UserAccount.groovy:369)
at domain.UserAccount$generateTokenLogin.callStatic(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:48)
at domain.UserAccount$generateTokenLogin.callStatic(Unknown Source)
at domain.UserAccount.setPwd(UserAccount.groovy:184)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1114)
根本原因是在某些奇怪的条件下存在creationDate
可能null
。我想解决方法不是在setter中调用generateTokenLogin()
(并且只在getter中调用)。
我无法解释为什么我们之前没有这个问题(没有最近的升级等)
答案 0 :(得分:0)
听起来好像一旦发生这种情况就不会在没有重启的情况下修复。我会看看你的应用程序的permgen大小。如果它适用于每个环境,那么期望生产就可能是内存问题。
简单的测试方法是添加200megs左右开始。
答案 1 :(得分:0)
只是一个疯狂的猜测 - 当你覆盖一个setter时,你不应该在这个setter中设置该字段的值,因为它是一种递归,或者至少是不可预知的行为(如此)可能是预期的,也许可以试试使用原始字段访问运算符:
public void setPwd(String pwd) {
this.@pwd = pwd
// We must recalculate token login
this.tokenLogin = generateTokenLogin(email, pwd)
}
email
字段/ setter
答案 2 :(得分:0)
您的pre-prod服务器与您的prod服务器完全相同吗? 你做的未成年人修改是哪些,你有没有影响?
可能是生成的战争包含错误,您是否尝试回滚修改?
Mayby你可以接受你的生产战争并把它放到你的预先制作的环境中来重现这个问题。
是否有来自插件,grails版本或依赖项中的任何内容的最新更新?
没有回答你的问题,但是我可以给你调查意见。
施奈特