Search code examples
rustrust-tokiorusoto

Rusoto async using FuturesOrdered combinator


I am trying to send off parallel asynchronous Rusoto SQS requests using FuturesOrdered:

use futures::prelude::*; // 0.1.26
use futures::stream::futures_unordered::FuturesUnordered;
use rusoto_core::{Region, HttpClient}; // 0.38.0
use rusoto_credential::EnvironmentProvider; // 0.17.0
use rusoto_sqs::{SendMessageBatchRequest, SendMessageBatchRequestEntry, Sqs, SqsClient}; // 0.38.0

fn main() {
    let client = SqsClient::new_with(
        HttpClient::new().unwrap(),
        EnvironmentProvider::default(),
        Region::UsWest2,
    );

    let messages: Vec<u32> = (1..12).map(|n| n).collect();
    let chunks: Vec<_> = messages.chunks(10).collect();

    let tasks: FuturesUnordered<_> = chunks.into_iter().map(|c| {
        let batch = create_batch(c);
        client.send_message_batch(batch)
    }).collect();

    let tasks = tasks
        .for_each(|t| {
            println!("{:?}", t);
            Ok(())
        })
        .map_err(|e| println!("{}", e));

    tokio::run(tasks);
}

fn create_batch(ids: &[u32]) -> SendMessageBatchRequest {
    let queue_url = "https://sqs.us-west-2.amazonaws.com/xxx/xxx".to_string();
    let entries = ids
        .iter()
        .map(|id| SendMessageBatchRequestEntry {
            id: id.to_string(),
            message_body: id.to_string(),
            ..Default::default()
        })
        .collect();

    SendMessageBatchRequest {
        entries,
        queue_url,
    }
}

The tasks complete correctly but tokio::run(tasks) doesn't stop. I assume that is because of tasks.for_each() will force it to continue to run and look for more futures?

Why doesn't tokio::run(tasks) stop? Am I using FuturesOrdered correctly?

I am also a little worried about memory usage when creating up to 60,000 futures to complete and pushing them into the FuturesUnordered combinator.


Solution

  • I discovered that it was the SqsClient in the main function that was causing it to block as it is still doing some house work even though the tasks are finished.

    A solution provided by one of the Rusoto people was to add this just above tokio::run

    std::mem::drop(client);