客观化 - 清理会话
Objectify - scavenging sessions
我原来的HttpSessionListener代码:
public class SessionListener implements HttpSessionListener {
@Override
public void sessionDestroyed(HttpSessionEvent event) {
final Object user = event.getSession().getAttribute("user");
if (user != null && user insteaceof User) {
UserUtils.deleteUser((User) user);
}
}
}
和我的web.xml
<filter>
<filter-name>ObjectifyFilter</filter-name>
<filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ObjectifyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
当 会话超时 事件发生时,它抛出:
WARNING: Problem scavenging sessions
java.lang.IllegalStateException: You have not started an Objectify context. You are probably missing the ObjectifyFilter. If you are not running in the context of an http request, see the ObjectifyService.run() method.
at com.googlecode.objectify.ObjectifyService.ofy(ObjectifyService.java:44)
at com.learnkeeper.server.OfyService.ofy(OfyService.java:61)
at com.learnkeeper.server.UserUtils.deleteUser(UserUtils.java:28)
at com.learnkeeper.server.SessionListener.sessionDestroyed(SessionListener.java:36)
at org.mortbay.jetty.servlet.AbstractSessionManager.removeSession(AbstractSessionManager.java:669)
at org.mortbay.jetty.servlet.AbstractSessionManager$Session.timeout(AbstractSessionManager.java:926)
at org.mortbay.jetty.servlet.HashSessionManager.scavenge(HashSessionManager.java:285)
at org.mortbay.jetty.servlet.HashSessionManager.access[=14=]0(HashSessionManager.java:44)
at org.mortbay.jetty.servlet.HashSessionManager.run(HashSessionManager.java:219)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
我试过了(来自这个 post How to resolve "You have not started an Objectify context" in JUnit?):
public class SessionListener implements HttpSessionListener {
private Closeable closeable;
@Override
public void sessionDestroyed(HttpSessionEvent event) {
final Object user = event.getSession().getAttribute("user");
if (user != null && user instanceof User) {
closeable = OfyService.begin();
UserUtils.deleteUser((User) user);
closeable.close();
}
}
}
这是我的 OfyService class:
class OfyService {
static {
// Register all my Entities classes
ObjectifyService.register(User.class);
...
}
public static Closeable begin() {
return ObjectifyService.begin();
}
public static ObjectifyFactory factory() {
return ObjectifyService.factory();
}
public static Objectify ofy() {
return ObjectifyService.ofy();
}
}
但相同 stacktrace :(
那么我错过了什么?
谢谢
编辑
跟进@stickfigure
所以我清理了我的项目并重新运行我的用例,现在我得到了这个堆栈跟踪:
WARNING: Problem scavenging sessions
java.lang.NullPointerException: No API environment is registered for this thread.
at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:132)
at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppIdNamespace(DatastoreApiHelper.java:148)
at com.google.appengine.api.datastore.Key.(Key.java:96)
at com.google.appengine.api.datastore.Key.(Key.java:78)
at com.google.appengine.api.datastore.KeyFactory.createKey(KeyFactory.java:54)
at com.google.appengine.api.datastore.KeyFactory.createKey(KeyFactory.java:47)
at com.googlecode.objectify.util.DatastoreUtils.createKey(DatastoreUtils.java:86)
at com.googlecode.objectify.impl.KeyMetadata.getRawKey(KeyMetadata.java:187)
at com.googlecode.objectify.impl.Keys.rawKeyOf(Keys.java:36)
at com.googlecode.objectify.impl.Keys.keyOf(Keys.java:29)
at com.googlecode.objectify.impl.LoaderImpl.entity(LoaderImpl.java:121)
at com.learnkeeper.server.UserUtils.deleteUser(UserUtils.java:28)
at com.learnkeeper.server.SessionListener.sessionDestroyed(SessionListener.java:40)
at org.mortbay.jetty.servlet.AbstractSessionManager.removeSession(AbstractSessionManager.java:669)
at org.mortbay.jetty.servlet.AbstractSessionManager$Session.timeout(AbstractSessionManager.java:926)
at org.mortbay.jetty.servlet.HashSessionManager.scavenge(HashSessionManager.java:285)
at org.mortbay.jetty.servlet.HashSessionManager.access[=15=]0(HashSessionManager.java:44)
at org.mortbay.jetty.servlet.HashSessionManager.run(HashSessionManager.java:219)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
我看不出该代码应该失败的任何原因,尽管它可以写得更优雅:
public class SessionListener implements HttpSessionListener {
@Override
public void sessionDestroyed(HttpSessionEvent event) {
final Object user = event.getSession().getAttribute("user");
if (user != null && user instanceof User) {
try (Closable closable = OfyService.begin()) {
UserUtils.deleteUser((User) user);
}
}
}
我的应用程序中有很多此代码的变体,并且在测试用例中有示例 - 实际上,所有 Objectify 的测试用例都依赖于此模式。
我想查看当您 运行 此代码时生成的确切堆栈跟踪。如果您正确调用了 begin()
,那么获得该堆栈跟踪应该是不可能的。您可以查看 ObjectifyService.ofy()
中的代码 - 它非常简单。仔细检查您部署的代码是否是您认为已部署的代码。
更新:新的堆栈跟踪非常不同,表明 GAE 未设置为执行来自该侦听器回调的 API 调用。它与 Objectify 无关;现在这是 Google 的问题。我建议写一个新问题来关注那个方面,并用 GAE 相关的标签来标记它。
也就是说,我的一般建议是避免依赖此回调。除了像这样的技术问题,我不相信它能在像 GAE 这样的分布式环境中一致地执行。如果你想让一个对象过期,在它上面放一个日期戳并剔除超过一周(或任何合理的时间)的任何东西。
Google App Engine Doesn't support session listeners. Session listeners may get invoke in local, but No API environment is registered for this thread. In production listeners will not even invoke.
来源@Ramesh V
无论如何谢谢@stickfigure
我原来的HttpSessionListener代码:
public class SessionListener implements HttpSessionListener {
@Override
public void sessionDestroyed(HttpSessionEvent event) {
final Object user = event.getSession().getAttribute("user");
if (user != null && user insteaceof User) {
UserUtils.deleteUser((User) user);
}
}
}
和我的web.xml
<filter>
<filter-name>ObjectifyFilter</filter-name>
<filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ObjectifyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
当 会话超时 事件发生时,它抛出:
WARNING: Problem scavenging sessions java.lang.IllegalStateException: You have not started an Objectify context. You are probably missing the ObjectifyFilter. If you are not running in the context of an http request, see the ObjectifyService.run() method. at com.googlecode.objectify.ObjectifyService.ofy(ObjectifyService.java:44) at com.learnkeeper.server.OfyService.ofy(OfyService.java:61) at com.learnkeeper.server.UserUtils.deleteUser(UserUtils.java:28) at com.learnkeeper.server.SessionListener.sessionDestroyed(SessionListener.java:36) at org.mortbay.jetty.servlet.AbstractSessionManager.removeSession(AbstractSessionManager.java:669) at org.mortbay.jetty.servlet.AbstractSessionManager$Session.timeout(AbstractSessionManager.java:926) at org.mortbay.jetty.servlet.HashSessionManager.scavenge(HashSessionManager.java:285) at org.mortbay.jetty.servlet.HashSessionManager.access[=14=]0(HashSessionManager.java:44) at org.mortbay.jetty.servlet.HashSessionManager.run(HashSessionManager.java:219) at java.util.TimerThread.mainLoop(Timer.java:555) at java.util.TimerThread.run(Timer.java:505)
我试过了(来自这个 post How to resolve "You have not started an Objectify context" in JUnit?):
public class SessionListener implements HttpSessionListener {
private Closeable closeable;
@Override
public void sessionDestroyed(HttpSessionEvent event) {
final Object user = event.getSession().getAttribute("user");
if (user != null && user instanceof User) {
closeable = OfyService.begin();
UserUtils.deleteUser((User) user);
closeable.close();
}
}
}
这是我的 OfyService class:
class OfyService {
static {
// Register all my Entities classes
ObjectifyService.register(User.class);
...
}
public static Closeable begin() {
return ObjectifyService.begin();
}
public static ObjectifyFactory factory() {
return ObjectifyService.factory();
}
public static Objectify ofy() {
return ObjectifyService.ofy();
}
}
但相同 stacktrace :(
那么我错过了什么? 谢谢
编辑
跟进@stickfigure
所以我清理了我的项目并重新运行我的用例,现在我得到了这个堆栈跟踪:
WARNING: Problem scavenging sessions java.lang.NullPointerException: No API environment is registered for this thread. at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:132) at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppIdNamespace(DatastoreApiHelper.java:148) at com.google.appengine.api.datastore.Key.(Key.java:96) at com.google.appengine.api.datastore.Key.(Key.java:78) at com.google.appengine.api.datastore.KeyFactory.createKey(KeyFactory.java:54) at com.google.appengine.api.datastore.KeyFactory.createKey(KeyFactory.java:47) at com.googlecode.objectify.util.DatastoreUtils.createKey(DatastoreUtils.java:86) at com.googlecode.objectify.impl.KeyMetadata.getRawKey(KeyMetadata.java:187) at com.googlecode.objectify.impl.Keys.rawKeyOf(Keys.java:36) at com.googlecode.objectify.impl.Keys.keyOf(Keys.java:29) at com.googlecode.objectify.impl.LoaderImpl.entity(LoaderImpl.java:121) at com.learnkeeper.server.UserUtils.deleteUser(UserUtils.java:28) at com.learnkeeper.server.SessionListener.sessionDestroyed(SessionListener.java:40) at org.mortbay.jetty.servlet.AbstractSessionManager.removeSession(AbstractSessionManager.java:669) at org.mortbay.jetty.servlet.AbstractSessionManager$Session.timeout(AbstractSessionManager.java:926) at org.mortbay.jetty.servlet.HashSessionManager.scavenge(HashSessionManager.java:285) at org.mortbay.jetty.servlet.HashSessionManager.access[=15=]0(HashSessionManager.java:44) at org.mortbay.jetty.servlet.HashSessionManager.run(HashSessionManager.java:219) at java.util.TimerThread.mainLoop(Timer.java:555) at java.util.TimerThread.run(Timer.java:505)
我看不出该代码应该失败的任何原因,尽管它可以写得更优雅:
public class SessionListener implements HttpSessionListener {
@Override
public void sessionDestroyed(HttpSessionEvent event) {
final Object user = event.getSession().getAttribute("user");
if (user != null && user instanceof User) {
try (Closable closable = OfyService.begin()) {
UserUtils.deleteUser((User) user);
}
}
}
我的应用程序中有很多此代码的变体,并且在测试用例中有示例 - 实际上,所有 Objectify 的测试用例都依赖于此模式。
我想查看当您 运行 此代码时生成的确切堆栈跟踪。如果您正确调用了 begin()
,那么获得该堆栈跟踪应该是不可能的。您可以查看 ObjectifyService.ofy()
中的代码 - 它非常简单。仔细检查您部署的代码是否是您认为已部署的代码。
更新:新的堆栈跟踪非常不同,表明 GAE 未设置为执行来自该侦听器回调的 API 调用。它与 Objectify 无关;现在这是 Google 的问题。我建议写一个新问题来关注那个方面,并用 GAE 相关的标签来标记它。
也就是说,我的一般建议是避免依赖此回调。除了像这样的技术问题,我不相信它能在像 GAE 这样的分布式环境中一致地执行。如果你想让一个对象过期,在它上面放一个日期戳并剔除超过一周(或任何合理的时间)的任何东西。
Google App Engine Doesn't support session listeners. Session listeners may get invoke in local, but No API environment is registered for this thread. In production listeners will not even invoke.
来源@Ramesh V
无论如何谢谢@stickfigure