Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std::marker::Send is not implemented for Rc<RefCell<actix_session::session::SessionInner>> #553

Closed
Oyelowo opened this issue May 29, 2022 · 1 comment

Comments

@Oyelowo
Copy link

Oyelowo commented May 29, 2022

Thanks for this wonderful library!

Issue

I am trying to use session object with Redis as the storage in a distributed system with async-graphql to set and delete session for userid but having issues with that because actix-session does not implement Send and cannot be moved across threads. It has type: Rc<RefCell<actix_session::SessionInner>>. async-graphql requires that it has a Send trait.

Full compiler error message:

`Rc<RefCell<actix_session::session::SessionInner>>` cannot be sent between threads safely
within `actix_session::Session`, the trait `std::marker::Send` is not implemented for `Rc<RefCell<actix_session::session::SessionInner>>`rustc[E0277](https://doc.rust-lang.org/error-index.html#E0277)
graphql.rs(74, 23): required by a bound introduced by this call
lib.rs(1, 1): required because it appears within the type `actix_session::Session`
request.rs(91, 26): required by a bound in `Request::data`
`Rc<RefCell<actix_session::session::SessionInner>>` cannot be shared between threads safely
within `actix_session::Session`, the trait `Sync` is not implemented for `Rc<RefCell<actix_session::session::SessionInner>>`rustc[E0277](https://doc.rust-lang.org/error-index.html#E0277)
graphql.rs(74, 23): required by a bound introduced by this call
lib.rs(1, 1): required because it appears within the type `actix_session::Session`

Question

  • Is there a possibility to make Session sendable?
#[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();  // ---> This is required to have `Send` marker
    request = request.data(session);

    schema.execute(request).await.into()
}

Present work around:

use std::ops::Deref;

use actix_session::Session;
use send_wrapper::SendWrapper;
use uuid::Uuid;
use wither::bson::oid::ObjectId;
#[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().unwrap()
    }
}

type SessionShared = Shared<actix_session::Session>;

#[derive(Debug, thiserror::Error)]
pub enum TypedSessionError {
    #[error("Failed to parse data")]
    ParsingFailure(#[from] serde_json::Error),

    #[error(transparent)]
    Unknown(#[from] anyhow::Error), // source and Display delegate to anyhow::Error
}

type TypedSessionResult<T> = Result<T, TypedSessionError>;

/*
This is somewhat like a hack: https://github.com/async-graphql/async-graphql/issues/426
Session is  Session(Rc<RefCell<SessionInner>>) and probably okay to use
SendWrapper for now but having it implement Send would allow
using Arc/Mutex
*/
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) -> TypedSessionResult<()> {
        self.0.insert(Self::USER_ID_KEY, user_id)?;
        Ok(())
    }

    pub fn get_user_uuid(&self) -> TypedSessionResult<Option<Uuid>> {
        Ok(self.0.get::<Uuid>(Self::USER_ID_KEY)?)
    }

    pub fn clear(&self) {
        self.0.clear()
    }
}

Pitfall to the workaround

The workaround uses a hack by Wrapping it in a SendWrapper. However, this is intended for when one is sure one is operating in a single-threaded context. However, this isn't the case for actix. So, I am considering this as a short-term solution

Also, curious why this isn't a common issue and why RefCell was used in the first place as Session type🤔

@robjtede robjtede changed the title std::marker::Send is not implemented for Rc<RefCell<actix_session::session::SessionInner>> std::marker::Send is not implemented for `Rc<RefCell<actix_session::session::SessionInner>> May 30, 2022
@robjtede robjtede changed the title std::marker::Send is not implemented for `Rc<RefCell<actix_session::session::SessionInner>> std::marker::Send is not implemented for Rc<RefCell<actix_session::session::SessionInner>> May 30, 2022
@robjtede
Copy link
Member

robjtede commented Jul 3, 2022

duplicate of actix/actix-extras#251

@robjtede robjtede closed this as completed Jul 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants