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

How to persist postgres sessions between server restarts or load balanced servers? #59

Closed
abcd-ca opened this issue Oct 12, 2023 · 2 comments

Comments

@abcd-ca
Copy link

abcd-ca commented Oct 12, 2023

I've almost got things working perfectly, I'm just missing one detail that I can't put my finger on. Here's what I've got:

  • axum
  • axum-session
  • async-sqlx-session

And here's a pared down version of main.rs

#[tokio::main]
async fn main() {
    let db_url = env::var("DATABASE_URL").unwrap();

    // session cookie ------ start
    let store = PostgresSessionStore::new(&db_url)
        .await
        .map_err(|e| {
            eprintln!("Database error: {:?}", e);
            RestAPIError::InternalServerError
        })
        .expect("Could not create session store.");
    store
        .migrate()
        .await
        .expect("Could not migrate session store.");
    store.spawn_cleanup_task(Duration::from_secs(60 * 60));
    // let mut session = Session::new();
    //
    // let cookie_value = store.store_session(session).await.unwrap().unwrap();
    // let session = store.load_session(cookie_value).await.unwrap();
    // println!("main session: {:?}", session);

    let secret = random::<[u8; 128]>();
    let session_layer = SessionLayer::new(store, &secret)
        .with_secure(true)
        .with_same_site_policy(SameSite::Strict)
        .with_persistence_policy(PersistencePolicy::ChangedOnly);
    // session cookie ------ end

    let routes_all = Router::new()
        .nest("/api/campaign", routes_campaign::routes())
        .layer(session_layer);

    // start server -------- start
    // Default IP as a fallback. This is what it should be for running on my local dev machine without Docker
    let default_ip = "127.0.0.1";

    let host: IpAddr = env::var("SERVER_LISTEN_HOST")
        .unwrap_or(default_ip.to_string()) // Use the default IP if the env variable is missing
        .parse() // Try parsing the string into an IpAddr
        .expect("Failed to parse host (listen on) IP address"); // If parsing fails, this will panic. You can handle this more gracefully if needed.

    let addr = SocketAddr::from((host, 8080));
    println!("Listening on {addr}\n");
    axum::Server::bind(&addr)
        .serve(routes_all.into_make_service())
        .await
        .unwrap();

    // start server -------- end
}

What I am finding is that the database session tables are getting updated correctly and the session persists between browser page reloads but if I stop my server and restart it, a new session is created and the old one is orphaned in the database. So, on start, the existing session is not being rehydrated. I think this must have something to do with the way the session is instantiated and is not using the sid cookie passed by the browser but I'm trying to work out what I need to modify.

Thanks for looking.

@maxcountryman
Copy link
Owner

maxcountryman commented Oct 12, 2023

Thanks for reporting this. We've since moved development to tower-sessions. Can I ask you to try migrating to that first?

@abcd-ca
Copy link
Author

abcd-ca commented Oct 12, 2023

@maxcountryman Thank you, I migrated to tower-sessions and it works like a charm. Only comment is that it's a bit harder to see the session data in the db when developing since it's a blob now rather than JSON string. The API is nicer now though and I like how the Postgres store is built in. Nice work, team!

@abcd-ca abcd-ca closed this as completed Oct 12, 2023
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