await()
メソッドはコンテキストを失うようです:
public static action() {
session.put("key", "value");
await(someAsyncCall());
// Now, for some reason the session doesn't have "key"
}
これは既知の問題ですか?回避策はありますか?
await()
メソッドはコンテキストを失うようです:
public static action() {
session.put("key", "value");
await(someAsyncCall());
// Now, for some reason the session doesn't have "key"
}
これは既知の問題ですか?回避策はありますか?
それは残念です。session はスレッド ローカル変数であるため、新しいスレッド間で渡されません (この例では発生します)。誤解を招き、驚くべきことは、コードが await メソッドの後に再開すると、セッション変数が存在することです (ただし、それは別のインスタンスです)。
これはバグだと思います-セッションコンテキストが await 呼び出しの周りに維持されることを期待しています。
とはいえ、これが難しい理由は理解できます。await を使用する場合、実際には少なくとも 3 つのスレッドでコードを記述しています。前の部分、ジョブ/非同期呼び出し、および後の部分。なぞってみると、なんだかすごい。
それでも、リクエストのセッション状態を維持する必要があることに同意するので、問題を報告することをお勧めします: https://play.lighthouseapp.com/projects/57987-play-framework /tickets/new
以下は、非同期呼び出しを介して渡すことによってセッション マップをコピーする回避策です。常にこれを行う単純なラッパー ジョブを作成できます。
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.set(session.getId(),userDataMap))。明らかに、それぞれのユースケースは異なるかもしれませんが、私はユーザーの状態を維持するためにこの方法を好みます。
Play 1.2.5 の回避策。セッション ID を永続化するだけでよい場合は、await(...) への直接呼び出しの代わりに以下を使用します。
protected static <T> T awaitSessionAware(Future<T> future) {
final String sessionId = session.getId();
T result = await(future);
session.put("___ID", sessionId);
return result;
}
上記のコードは、既存のセッションを再利用する代わりに、await(..) 呼び出しの後に新しいセッションが作成されるという、ここで概説した問題の回避策です。元のセッション ID への参照は、await 呼び出しの後にセッション ID をリセットするために使用されます (つまり、session.put("___ID", sessionId) はセッション ID を待機前の値にリセットします)。