Context
I have an actix-web server (v 4.0) which has two end-points, namely, /insert and /read These end-points serve as an abstraction to insert to or read from a postgres (v 14.5) table (being used with diesel ORM). Multiple users can query the system with their own tokens which resolve into a user_id. The postgres table has RLS enabled which allows each user_id to interact with just their rows. When either endpoint is hit, a session variable is set in postgres which equates to the requester's user_id thus making only their rows visible to them. Just before the request's completion, the session variable is reset to its default value.
Code Snippets
These functions are an over-simplified representation of the actual end-point functions
pub fn insert(
user_id: &str,
pg_conn: &mut PgConnection,
data_to_insert: Vec<String>,
) -> anyhow::Result<()> {
// initiate a transaction
let res = pg_conn.transaction::<_,anyhow::Error,_>(|pg_conn| {
for row in data_to_insert {
sql_query(format!("SET SESSION myapp.user_id = '{user_id}';")).execute(pg_conn)?;
// running in a for-loop because in reality I'm doing "on conflict, do update"
// insert
diesel::insert_into(contacts::table)
.values(&row)
.execute(pg_conn)?;
}
sql_query("SET SESSION myapp.user_id = -1;").execute(pg_conn)?;
Ok(())
});
}
pub fn read(
pg_conn: &mut PgConnection,
user_id: &str
) -> anyhow::Result<Vec<DataStruct>> {
sql_query(format!("SET SESSION myapp.user_id = '{user_id}';")).execute(pg_conn)?;
let data: Vec<DataStruct> = data::table.load(pg_conn)?;
sql_query("SET SESSION myapp.user_id = -1;").execute(pg_conn)?;
Ok(data)
}
The Issue
While writing tests for the application explained above, I wanted to see how the system would behave in case of multiple simultaneous requests. I wrote a test in Rust which would simulate two users sending multiple requests to both read and insert using Rayon. The test however called the functions directly instead of sending an actual HTTP request. Unsurprisingly, the test failed as the first user's data was sometimes being served to the second user. To make the test more accurate (and correct), I created a small cargo project which would send multiple HTTP requests to the server simultaneously (for both the users). And this test passed! So basically, I want to know how is actix handling such situations where multiple requests are coming in for the same endpoint and doing their computation in isolation(?) especially when an external program like Postgres is involved.