Play async / await中的会话/上下文丢失

时间:2012-12-31 08:46:02

标签: playframework playframework-1.x

似乎await()方法失去了上下文:

public static action() {
    session.put("key", "value");
    await(someAsyncCall());

    // Now, for some reason the session doesn't have "key"
}

这是一个已知问题吗?任何解决方法?

2 个答案:

答案 0 :(得分:2)

这很不幸。由于session是一个线程局部变量,因此它不会在新线程之间传递(在您的示例中会发生)。什么是误导和令人惊讶的是,当代码在await方法之后恢复时,会有一个会话变量(但它是一个不同的实例)。

我想说这是一个错误 - 我希望在await调用周围保持会话上下文。

那就是说,我理解为什么这很棘手。当你使用await时,你实际上是在至少三个线程中编写代码。前一部分,作业/异步调用和后续部分。追踪它,它真是太棒了。

即便如此,我同意应保留请求的会话状态,因此我建议您提出问题:https://play.lighthouseapp.com/projects/57987-play-framework/tickets/new

下面是一种解决方法,通过传递异步调用来复制会话映射。您可以编写一个简单的包装器Job,它始终执行此操作。

public static void test() {
    Logger.debug("before: Session.current() " + Session.current());
    Session.current().put("key", new Date().toString());
    Job<Session> async = new Job<Session>() {
        Session sessionPassed = Session.current();

        @Override
        public Session doJobWithResult() throws Exception {
            Logger.debug("during job: Session.current() "
                    + Session.current());
            Logger.debug("during job: sessionPassed " + sessionPassed);
            Thread.sleep(1000L);

            // you could do something like this to wrap a real 
            // async call and maintain the session context.  If 
            // the async job returns a result, you'll have to return 
            // a map or POJO with the session and the result.

            actualJob.now();  

            return sessionPassed;
        }
    };
    Session sessionReturned = await(async.now());
    Logger.debug("after: Session.current() ="
            + (Session.current() == null ? "no session" : Session.current()));
    Logger.debug("after: " + sessionReturned);

    Session.current().all().putAll(sessionReturned.all());

    Logger.debug("finally: "
            + (Session.current() == null ? "no session" : Session.current()));
}

编辑:

或者,您可以使用Cache.set()存储会话映射 - 这可能比传递它更清晰。

另外,我很少使用会话来存储用户数据。每个cookie(这是会话正在播放的内容)会减慢您的http请求(了解Cookie如何工作)。我更喜欢做的是使用Cache在服务器端创建一个映射(例如Cache.set(session.getId(),userDataMap))。显然每个用例可能不同,但我更喜欢这种方式来维护用户状态。

答案 1 :(得分:0)

Play 1.2.5的解决方法,如果只需要保留会话ID,请使用以下内容代替直接调用等待(...)

protected static <T> T awaitSessionAware(Future<T> future) {
    final String sessionId = session.getId();
    T result = await(future);
    session.put("___ID", sessionId);
    return result;
}

上面的代码是针对here概述的问题的解决方法,其中在await(..)调用之后创建新会话,而不是重用现有会话。对原始会话ID的引用用于在等待调用之后重置会话ID(即session.put(&#34; ___ ID&#34;,sessionId)将会话ID重置为其预等待值)。