Actix - how do I set LRUCache as a data provider to an endpoint?

I have a working example using MySQL in an Actix endpoint. The gist of it is here:

extern crate mysql;

use actix_web::web::{Data};
use actix_web::{get, App, Error, HttpResponse, HttpServer, web};


use r2d2_mysql::mysql::{Opts,OptsBuilder};

use serde::Serialize;
use r2d2::Pool;

use r2d2_mysql::MysqlConnectionManager;
use r2d2_mysql::mysql::prelude::Queryable;


#[derive(Serialize)]
pub struct Organization {
    pub id: Option<i32>,
    pub name: String,
    pub country: String
}

#[get("/orgs")]
async fn get_orgs(
    pool: Data<Pool<MysqlConnectionManager>>,
) -> Result<HttpResponse, Error> {
    let mut conn = pool
        .get()
        .map_err(|_| HttpResponse::InternalServerError())?;

    let orgs = conn
        .query_map(
            "SELECT id, name, country from organization",
            |(id, name, country)| {
                Organization { id, name, country }
            },
        ).map_err(|_| HttpResponse::InternalServerError())?;

    Ok(HttpResponse::Ok().json(orgs))
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let opts = Opts::from_url("mysql://root:mysql@127.0.0.1:33061/ebdb").unwrap();
    let builder = OptsBuilder::from_opts(opts);
    let m = MysqlConnectionManager::new(builder);

    let p = Pool::new(m).unwrap();

    let cache = set_mysql_orgs(p.clone());

    HttpServer::new(move || App::new()
        .data(p.clone())
        .service(get_orgs))
        .bind("127.0.0.1:8090")?
        .run()
        .await
}

Which works!

Now, I want to try to populate an in-memory cache to get a single "org". How do I provide an LRU Cache to an Actix endpoint?

Example code that definitely does not work:

extern crate mysql;

use actix_web::web::{Data};
use actix_web::{get, App, Error, HttpResponse, HttpServer, web};


use r2d2_mysql::mysql::{Opts,OptsBuilder};

use serde::Serialize;
use r2d2::Pool;

use r2d2_mysql::MysqlConnectionManager;
use r2d2_mysql::mysql::prelude::Queryable;
use lru::LruCache;
use r2d2_mysql::mysql::uuid::Uuid;


#[derive(Serialize)]
pub struct Organization {
    pub id: Option<i32>,
    pub name: String,
    pub country: String
}

fn set_mysql_orgs(pool: Pool<MysqlConnectionManager>) -> LruCache<Option<i32>, Organization, ()> {
    let mut conn = pool
        .get()
        .map_err(|_| HttpResponse::InternalServerError())?;

    let orgs = conn
        .query_map(
            "SELECT id, name, country from organization",
            |(id, name, country)| {
                Organization { id, name, country }
            },
        ).map_err(|_| HttpResponse::InternalServerError())?;

    // populate the cache with the orgs by ID
    let mut cache = LruCache::new(500);
    for org in orgs {
        cache.put(org.id, org);
    }

    cache
}


#[get("/org/{id}")]
async fn get_org(org_id: web::Path<Uuid>) -> Result<HttpResponse, Error> {
    let org_id = org_id.into_inner();

    let org = cache.get(&org_id);

    Ok(HttpResponse::Ok().json(org))
}


#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let opts = Opts::from_url("mysql://root:mysql@127.0.0.1:33061/ebdb").unwrap();
    let builder = OptsBuilder::from_opts(opts);
    let m = MysqlConnectionManager::new(builder);

    let p = Pool::new(m).unwrap();

    let cache = set_mysql_orgs(p.clone());

    HttpServer::new(move || App::new()
        .data(p.clone())
        .service(get_org))
        .bind("127.0.0.1:8090")?
        .run()
        .await
}

I want to:

  1. Populate the cache in fn main
  2. Somehow provide the data(cache) to the get_org endpoint instead of MySQL.
  3. Parse the org_id in get_org, look up the cache, return the org if it's there.

I'm very new to Rust, so apologies for the "big" question. Trying to learn on the go, but I get stuck sometimes where I end up brute-forcing my way out of problems using thought of languages I already know(Go), which is probably a bad idea.

(Consider the last example almost pseudo code.. Definitely wont compile)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.