Tokio thread is not starting / spawning - rust

I'm trying to start a new task to read from a socket client. I'm using the following same method on both the websocket server and client to receive from the connection.
The problem is, on the server side, the thread is started (2 log lines printed), but on the client side the thread is not starting (only the first line printed).
If I await on the spawn(), I can receive from the client. But then the parent task cannot proceed.
Any pointers for solving this problem?
pub async fn receive_message_from_peer(
mut receiver: PeerReceiver,
sender: Sender<IoEvent>,
peer_index: u64,
) {
debug!("starting new task for reading from peer : {:?}", peer_index);
tokio::task::spawn(async move {
debug!("new thread started for peer receiving");
// ....
}); // not awaiting or join!()

Do you use tokio::TcpListener::from_std(...) to create a listener object this way?
I had the same problem as you, my std_listener object was created based on net2. So there is a scheduling incompatibility problem.
From the description in the newer official documentation https://docs.rs/tokio/latest/tokio/net/struct.TcpListener.html#method.from_std, it seems that tokio currently has better support for socket2.

So I think the issue was I was using std::thread::sleep() in async code in some places. after using tokio::time::sleep() didn't need to yield the thread.

Related

How to establish external timeout for notify-rust

I'm trying to use notify-rust library on Ubuntu 20.04, but the notifications that are emitted have unpredictable timeouts. Also, if I send several notifications with short delays between them, the results may vary (sometimes I see all notifications, sometimes only several of them).
The workarounds I applied:
Critical Urgency, so the notifications would stay displayed forever.
Wait for an action before displaying the next notification, so no notifications would be lost.
// add `notify-rust = "4"` to dependencies for this code to work
use notify_rust::{Notification, Urgency};
use std::{thread, time};
fn main() {
let summaries = ["one", "two"];
for summary in summaries {
let handle = Notification::new()
.summary(summary)
.urgency(Urgency::Critical)
.show()
.unwrap();
// helps displaying all the notifications
handle.wait_for_action(|_action| ());
// delay might vary
thread::sleep(time::Duration::from_millis(10));
}
}
I also experimented with the lib's timeout, but didn't get any good results.
The primary issue with the wait_for_action approach, is that sometimes no notification is seen on the screen after it was sent, so the main thread is waiting for an action on that notification that would never happen (nothing to click on).
I want to try a watchdog approach: start a thread, send the notification handler into it, and close the notification after some timeout:
let handle = Notification::new()
...
let thread_handle = handle.clone();
thread::spawn(move || {
thread::sleep(time::Duration::from_secs(60));
thread_handle.close();
});
handle.wait_for_action(|_action| ());
I'm not sure how to do that part. I can't use handle both for the thread and for wait_for_action, because the thread takes the ownership. Cloning doesn't work properly, instead of NotificationHandle it produces Notification.
Is there any way to solve this without dip dig into notify-rust library internals?
I think I can resolve this using the whole different approach that won't involve calling blocking wait_for_action, but I wonder if there is any more elegant solution?
I came up with another algorithm for notifications and timeouts: instead of relying on wait_for_action being able to catch an event of a notification being closed, I created two threads:
one with the same wait_for_action that on completion sends a message through a channel
another thread that waits for some time and then sends the same message through the same channel
The main thread waits for the message and continues as the first message arrives.
use notify_rust::{Notification, Urgency};
use std::sync::mpsc;
use std::{thread, time};
fn main() {
let summaries = ["one", "two"];
for summary in summaries {
// establish the channel and a second transmitter for `timeout` thread
let (handler_tx, rx) = mpsc::channel();
let timer_tx = handler_tx.clone();
// no changes here
let handler = Notification::new()
.summary(summary)
.urgency(Urgency::Critical)
.show()
.unwrap();
// `wait_for_action` is wrapped into a thread
thread::spawn(move ||
handler.wait_for_action(|_action|
handler_tx.send(()).unwrap_or(())
)
);
// another thread that waits and then sends the same message
thread::spawn(move || {
thread::sleep(time::Duration::from_secs(7));
timer_tx.send(()).unwrap_or(());
});
// the main thread that waits for a message from any of senders
rx.recv().unwrap();
thread::sleep(time::Duration::from_millis(10));
}
}
Results of message sending are ignored on purpose: only one of those messages could be sent successfully, then the channel goes out of scope and another sender gets an error, and that's fine.
The solution has a disadvantage: it's possible that after the timeout, another notification would be sent without waiting for the previous one to be closed. I saw those notifications still can be displayed after the first one be closed even if the main thread finished, so they were waiting on the notification bus.
I also noted that there is another method implemented for NotificationHandler that probably suits better this task: on_close, but it is implemented using wait_for_action, so it's also blocking, and I can't implement notification close after timeout using this method.

Making channels constructioned in a function last the lifetime of the program in Rust

I'm trying to write a basic multithreaded application using gtk3-rs, where the main thread sends a message to a child thread when a button is clicked, and the child thread sends a message back in response, after doing some calculations, the results of which are displayed by the main thread in a dialog box.
This seems simple enough conceptually, but I'm running into a problem where the channels that I'm creating in the callback that is used by gtk::Application::connect_activate to build the user interface are getting closed before the child thread (also created in that callback, and then detached) can even use them once, let alone how I intended, which is continually throughout the life of the application.
These are glib channels on the MainContext, not MSPC channels, so instead of busy-waiting for input like for normal channels, I was able to attach a listener on both receivers. I have one listening in the main thread (attached in the UI builder callback) and one listening in the spawned thread, but apparently that's not enough to keep the channels alive, because when I try to send a message to the thread's channel, it errors out saying that the thread is closed.
So the basic structure of my code is like this:
fn connect_events(/* event box, channel a */) {
event_box.connect_button_release_event(move |_, _| {
a.send("foo").unwrap();
});
}
fn build_ui(app: &gtk::Application) {
let (a, b) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
let (c, d) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
let event_box = /* GTK event box to capture events */;
connect_events(&event_box, a.clone());
thread::spawn(move || {
b.attach(/* handle receiving a message from the main thread by sending a message back on c */);
});
d.attach(/* pop up a dialog box with whatever was sent back */);
}
fn main() {
let application = gtk::Application::new(
Some("com.example.aaaaaaaa"),
Default::default(),
);
application.connect_activate(build_ui);
application.run();
}
So, how do I convince Rust to keep the channels alive? I tried doing some lazy_static magic and using .leak(), but neither of those seemed to work, and moving all of this code out of the UI builder is unfortunately not an option.
My pragmatic answer is: Don't use glib channels.
I'm using async rust channels for things like this. In your case, a oneshot channel could be useful. But many crates provide async channels, async-std or tokio for example.
You can spawn a function via glib::MainContext::default().spawn_local() that .awaits the message(s) from the channel and show the dialog there.

how to get current thread(worker) in rust rocket

Now I am using rust rocket rocket = { version = "0.5.0-rc.1", features = ["json"] } as a web server, I am facing a problem when the request quickly, some request may turn to time out, my server side code look like this:
#[post("/v1",data = "<record>")]
pub fn word_search(record: Json<WordSearchRequest>, login_user_info: LoginUserInfo) -> content::Json<String> {
// some logic to fetch data from database
}
I was wonder why the requst turned to time out, so I want to print the server side thread and handle request time. is it possible to get current thread id in rust rocket? I am seriously doubt the server only have one thread.
I finnally found the server only have one worker from the log ouput, then I add more workers in the Rocket.toml config file fix the timeout problem.
[release]
workers = 12
log_level = "normal"
keep_alive = 5
port = 8000

Do a synchronous http client fetch within an actix thread

I have an actix endpoint, and I need to do a synchronous http client fetch to get some results, and return some data. My endpoints cannot use async, so I can't use any .await methods.
I've tried using reqwests blocking client in my endpoint like so:
{ ...
let res = reqwest::blocking::get(&fetch_url)?
.json::<MyResp>()?;
...
But it gives me the error:
thread 'main' panicked at 'Cannot start a runtime from within a runtime. This happens because a function (like `block_on`) attempted to block the current thread while the thread is being used to drive asynchronous tasks.', /.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.9/src/runtime/enter.rs:19:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
you should try creating a new thread for that:
std::thread::spawn(move || {
reqwest::blocking::get(&url).unwrap().json().unwrap()
}).join().unwrap()
I couldn't figure out how to get it working with reqwest (it must have some weird conflicts with actix), but for some reason it worked fine with chttp.
chttp::get(&fetch_url)?.text()?;
You cannot use blocking functions inside async functions.
Instead of reqwest::blocking::get() use reqwest::get().await.

a request-method in java that implements long-polling

I have already written a request-method in java that sends a request to a simple Server. I have written this simple server and the Connection is based on sockets. When the server has the answer for the request, it will send it automatically to client. Now I want to write a new method that can behave as following:
if the server does not answer after a fixed period of time, then I send a new Request to the server using my request-method
My problem is to implement this idea. I am thinking in launching a thread, whenever the request-method is executed. If this thread does not hear something for fixed period of time, then the request method should be executed again. But how can I hear from the same socket used between that client and server?
I am also asking,if there is a simpler method that does not use threads
curently I am working on this idea
I am working on this idea:
1)send a request using my request-method
2)launch a thread for hearing from socket
3)If(no answer){ go to (1)}
else{
exit
}
I have some difficulties in step 3. How I can go to (1)
You may be able to accomplish this with a single thread using a SocketChannel and a Selector, see also these tutorials on SocketChannel and Selector. The gist of it is that you'll use long-polling on the Selector to let you know when your SocketChannel(s) are ready to read/write/etc using Selector#select(long timeout). (SocketChannel supports non-blocking, but from your problem description it sounds like things would be simpler using blocking)
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
Selector selector = Selector.open();
SelectionKey key = socketChannel.register(selector, SelectionKey.OP_READ);
// returns the number of channels ready after 5000ms; if you have
// multiple channels attached to the selector then you may prefer
// to iterate through the SelectionKeys
if(selector.select(5000) > 0) {
SocketChannel keyedChannel = (SocketChannel)key.channel();
// read/write the SocketChannel
} else {
// I think your best bet here is to close and reopen the Socket
// or to reinstantiate a new socket - depends on your Request method
}
I am working on this idea:
1)send a request using my request-method
2)launch a thread for hearing from socket
3)If(no answer) then go to (1)

Resources