async_nursery 0.5.0

Primitive for structured concurrency
Documentation
//! With an executor from async_executors you can use the timeout method to limit the life
//! time of spawned tasks. Tasks that time out are dropped and no result is sent to the
//! output stream.
//!
//! Expected output in 3 seconds:
//!
//! $ cargo run --example resource_await
//!
//! INFO timeout: nursery created
//! INFO timeout: spawned slow 0
//! INFO timeout: spawned slow 3
//! INFO timeout: spawned slow 4
//! INFO timeout: spawned slow 1
//! INFO timeout: spawned slow 2
//! INFO timeout: completed slow 0
//! INFO timeout: completed slow 1
//! INFO timeout: completed slow 2
//! INFO timeout: drop Nursery and NurseryStream
//!
mod common;

use
{
	async_executors :: { AsyncStd, TimerExt       } ,
	async_nursery   :: { Nursery, NurseExt        } ,
	common          :: { DynResult, setup_tracing } ,
	futures_timer   :: { Delay                    } ,
	std             :: { time::Duration           } ,
	tracing_crate   :: { info                     } ,
};



async fn resource_await( amount: usize ) -> DynResult<()>
{
	let (nursery, output) = Nursery::new( AsyncStd ); info!( "nursery created" );
	let delay = Duration::from_secs(2);

	for i in 0..amount
	{
		let task = nursery.timeout( delay, slow(i) );
		nursery.nurse( task )?;
	}

	// This is necessary. Since we could keep spawning tasks even after starting to poll
	// the output, it can't know that we are done, unless we drop all senders or call
	// `close_nursery`. If we don't, the await below deadlocks.
	//
	drop(nursery);

	// Resolves when all spawned tasks are done.
	//
	output.await;

	info!( "drop Nursery and NurseryStream" );
	Ok(())
}



async fn slow( seconds: usize ) -> DynResult<()>
{
	info!( "spawned slow {}", seconds );

	Delay::new( Duration::from_secs(seconds as u64) ).await;

	info!( "completed slow {}", seconds );

	Ok(())
}



#[ async_std::main ]
//
async fn main() -> DynResult<()>
{
	setup_tracing();

	resource_await( 5 ).await?;

	Ok(())
}