会话/上下文在Play异步/等待中丢失 [英] Session/context lost in Play async/await

查看:114
本文介绍了会话/上下文在Play异步/等待中丢失的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

It seems the await() method loses context:

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

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

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

Is this a known issue? Any workarounds?

推荐答案

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

That is unfortunate. Since session is a thread local variable it does not get passed between new threads (which happens in your example). What is misleading and surprising, is that when the code resumes after the await method there is a session variable (but it is a different instance).

我会说这是一个错误-我希望会话上下文可以在await调用周围维护.

I would say this is a bug - I'd expect the session context to be maintained around the await call.

也就是说,我理解为什么这很棘手.当使用await时,实际上是在至少三个线程中编写代码.之前的部分,作业/异步调用和之后的部分.追溯到它,真是太神奇了.

That said, I understand why this is tricky. When you use await, you are actually writing code in at least three threads. The before part, the job/async call, and the after part. Trace into it, it is kind of amazing.

即使如此,我同意应该维护请求的会话状态,所以我建议您提出一个问题:

Even so, I agree that the session state for the request should be maintained, so I suggest you file an issue: https://play.lighthouseapp.com/projects/57987-play-framework/tickets/new

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

Below is a workaround that copies the session map by passing it through the async call. You could write a simple wrapper Job that always does this.

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()存储会话映射-也许比传递它干净.

Alternatively, you could store the session map using Cache.set() - this is perhaps cleaner than passing it around.

顺便说一句,我很少使用会话来存储用户数据.每个cookie(会话正在进行中)都会减慢您的http请求(了解cookie的工作原理).我更喜欢做的是使用Cache在服务器端创建一个映射(例如Cache.set(session.getId(),userDataMap)).显然,每个用例可能有所不同,但是我更喜欢这种方式来维护用户状态.

As an aside, I seldom use session to store user data. Each cookie (which is what a session is in play) slows down your http requests (read about how cookies work). What I prefer to do is create a map on the server side using the Cache (eg Cache.set(session.getId(),userDataMap)). Clearly each use case may be different, but I prefer this way to maintain user state.

这篇关于会话/上下文在Play异步/等待中丢失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆