如何在异步graphql解析器中使用activx-redis会话



我正试图在signinsignupsignout解析器中使用具有Redis的会话对象作为分布式系统中的存储,以设置和删除userid的会话,但由于activx的Session没有实现Send,无法跨线程使用,因此存在问题。类型:Rc<RefCell<actix_session::SessionInner>>

问题

  • async-graphql中处理此类问题的惯用方法是什么?我想做如下事情:
#[Object]
impl User {
async fn signin(&self, ctx: &Context<'_>) -> anyhow::Result<Vec<User>> {
let session = ctx.data_unchecked::<Session>();
session.insert("user_id", id);
session.get::<UserId>("user_id");
...
}
}

如果我尝试以上操作,我会得到:

`Rc<RefCell<actix_session::SessionInner>>` cannot be shared between threads safely
within `actix_session::Session`, the trait `Sync` is not implemented for `Rc<RefCell<actix_session::SessionInner>>`
  • 此外,在异步graphql上下文中创建session的正确位置在哪里?我正在尝试,但会面临同样的问题:
#[post("/graphql")]
pub async fn index(
schema: web::Data<MyGraphQLSchema>,
req: HttpRequest,
gql_request: GraphQLRequest,
) -> GraphQLResponse {
let mut request = gql_request.into_inner();
let session = req.get_session();
request = request.data(session);
schema.execute(request).await.into()
}

我的应用程序:

let redis_key = Key::from(hmac_secret_from_env_var.expose_secret().as_bytes());
App::new()
.wrap(cors)
.wrap(
RedisSession::new(redis.get_url(), redis_key.master())
.cookie_http_only(true)
// allow the cookie only from the current domain
.cookie_same_site(cookie::SameSite::Lax),
)
.wrap(Logger::default())

我使用临时破解解决了这个问题。如果您检查会话定义,您会注意到它将RefCell包装如下,并且不实现send

pub struct Session(Rc<RefCell<SessionInner>>);

理想情况下,Session应该实现sync,这样我们就可以在多线程上下文中使用它。

我目前使用的方法是用SendWrapper进行包装,这并不理想,因为当你确信包装的项目将以单线程方式使用时,这是不理想的。

use std::ops::Deref;
use actix_session::Session;
use actix_web::Error;
use send_wrapper::SendWrapper;
use uuid::Uuid;
#[derive(Clone, Debug)]
struct Shared<T>(pub Option<SendWrapper<T>>);
impl<T> Shared<T> {
pub fn new(v: T) -> Self {
Self(Some(SendWrapper::new(v)))
}
}
impl<T> Deref for Shared<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.0.as_deref().clone().unwrap()
}
}
type SessionShared = Shared<actix_session::Session>;

pub struct TypedSession(SessionShared);
impl TypedSession {
const USER_ID_KEY: &'static str = "user_id";
pub fn new(session: Session) -> Self {
Self(Shared::new(session))
}
pub fn renew(&self) {
self.0.renew();
}
pub fn insert_user_uuid(&self, user_id: Uuid) -> Result<(), Error> {
self.0.insert(Self::USER_ID_KEY, user_id)
}
pub fn get_user_uuid(&self) -> Result<Option<Uuid>, Error> {
self.0.get::<Uuid>(Self::USER_ID_KEY)
}
pub fn clear(&self) {
self.0.clear()
}
}

最新更新