Handling shared state between actix and a parallel thread In order to learn rust and concurrency , im trying to share a common hashmap between actix web server and a parallel thread

Theres one thread which updates a hashmap with the current timestamp every 10 seconds
theres a GET API which returns the latest timestamp provided in the hashmap

heres my code
use actix_web::{web, App, HttpServer};
use std::collections::HashMap;
use chrono::prelude::*;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

async fn get_latest_timestamp(data: web::Data&lt;Arc&lt;Mutex&lt;HashMap&lt;String, String&gt;&gt;&gt;&gt;) -&gt; String {
    
    let wrapped_data = data.lock().unwrap();

    match wrapped_data.get(&quot;time_now&quot;) {
        Some(i) =&gt; String::from(i),
        None =&gt; String::from(&quot;None&quot;)
    }
}

fn update_timestamps(data: Arc&lt;Mutex&lt;HashMap&lt;String, String&gt;&gt;&gt;) -&gt; () {

    loop {
        thread::sleep(Duration::from_secs(10));
        println!(&quot;Updating time.... &quot;);
        let now: DateTime&lt;Local&gt; = Local::now();

        let mut data = data.lock().unwrap();
    
        data.insert(String::from(&quot;time_now&quot;), now.to_rfc2822());
    }
}


#[actix_web::main]
async fn main() -&gt; std::io::Result&lt;()&gt; {

    let mut hash = HashMap::new();
    hash.insert(String::from(&quot;time_now&quot;), Local::now().to_rfc2822());

    let data = Arc::new(Mutex::new(hash));

    let hash_clone = Arc::clone(&amp;data);
    thread::spawn(move || {
        update_timestamps(hash_clone)
    });

    HttpServer::new( move || {
        App::new()
            .data(data.clone())
            .route(&quot;/&quot;, web::get().to(get_latest_timestamp))
    })
    .bind(&quot;127.0.0.1:8080&quot;)?
    .run()
    .await
}

Is there anything i could do handle better. A couple of questions i do have

How does one generally handle errors that occur on the parallel thread? is the main thread notified in someway?

the code in update_timestamps runs in a continous loop - is there a better way to handle it so that it cleanly exits?
Answering your questions:

Depends on the nature of the error.

Panics will make the thread exit. If the creator called join on the result of thread::spawn, the result of that join will be Err(boxed_any). The boxed_any is the argument given to panic!. This is one common way to signal and handle an error.
If the panic occurs while a mutex's lock is in scope, the mutex will be poisoned and therefore return Err for all locking attempts on all threads indefinitely.
In case you'd like to notify another thread about an event, let's say, an occurence of a meaningful error, it's best to use channels. You can read more in &quot;Using Message Passing to Transfer Data Between Threads&quot;: https://doc.rust-lang.org/book/ch16-02-message-passing.html

I'm not sure what you meant by exiting cleanly. You need the thread to run indefinitely. The thread will exit &quot;cleanly&quot; when the server is closed (and so when the main thread exits).

Minor points:

calls to Arc::clone can be simply .clone(). Quoting the docs:

// The two syntaxes below are equivalent.
let a = foo.clone();
let b = Arc::clone(&amp;foo);


the second (and last) data.clone() is unnecessary. This is often seen in code. Just pass the value.

You still have ownership of that original value. That original value can be spent by passing it to actix.

-&gt; () in a function signature is never meaningful; just cut it out.