graphql-rust / juniper

GraphQL server library for Rust
Other
5.72k stars 425 forks source link

How do I access an Actix Web session store from a resolver? #1128

Closed forty1thousand closed 1 year ago

forty1thousand commented 2 years ago

I have a project going where I need to store state inside of a session object and need to access it from inside of both a query and mutation resolver.

Here is a simple version of my current code.

graphql.rs

use actix_session::Session;
use juniper::graphql_object;

pub struct MyCtx {
    ses: Session,
}

#[graphql_object(context = MyCtx)]
impl Query {
    // ...
}
// ...

endpoints.rs

use crate::graphql::{Schema, MyCtx};
use actix_session::Session;
use actix_web::{HttpResponse, Error, HttpRequest, web::{Payload, Data}};

pub async fn graphql(
    req: HttpRequest,
    payload: Payload,
    schema: Data<Schema>,
    ses: Session
) -> Result<HttpResponse, Error> {
    let ctx = MyCtx { ses };
    graphql_handler(&schema, &ctx, req, payload).await
}
// ...

This code gives me a thread safety error when I run it.

`Rc<RefCell<actix_session::session::SessionInner>>` cannot be shared between threads safely
within `MyCtx`, the trait `Sync` is not implemented for `Rc<RefCell<actix_session::session::SessionInner>>`

I know the session store can also be accessed from a HttpRequest object but that also returns the same error.

Is there a workaround or an example of this being done?

ilslv commented 2 years ago

@forty1thousand actix uses a bunch of single-threaded tokio runtimes instead of a single multi-threaded to avoid overhead of work stealing, so many types are !Send. Due to limitations in Rust type system we can't be transparent over Send and Sync, but here it actually should be ok to use SendWrapper, which moves Send check into a runtime.

See

tyranron commented 1 year ago

@forty1thousand I'm closing this as @ilslv gave the working solution, which we do use in our production without problem. Feel free to re-open if there are further questions.

forty1thousand commented 1 year ago

Is there an example of this being done somewhere