Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Aug 12, 2022. It is now read-only.
/simulationPublic archive

Framework for simulating distributed applications

NotificationsYou must be signed in to change notification settings

tokio-rs/simulation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

43 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

The Simulation library is being refactored to integrate more directly with Tokio. Currently, Simulation is not compatible with Tokio 0.2.x. As a result, it's recommended that users wait for a future release of Simulation. The issue tracking Tokio integration progress can be found heretokio-rs/tokio#1845.

simulation

The goal of Simulation is to provide a set of low level components which can beused to write applications amenable toFoundationDB style simulation testing.

Simulation is an abstraction overTokio, allowing application developers to writeapplications which are generic over sources of nondeterminism. Additionally, Simulationprovides deterministic analogues to time, scheduling, network and eventually disk IO.

Scheduling and Time

Simulation provides a mock source of time. Mock time will only advance when the executorhas no more work to do. This can be used to force deterministic reordering of task execution.

When time is advanced, it is advanced instantly to a value which allows the executor to makeprogress. Applications which rely on timeouts can then be tested in a fraction of the time itwould normally take to test a particular execution ordering.

This can be used to naturally express ordering between tasks

use simulation::{Environment};#[test]fnordering(){letmut runtime =DeterministicRuntime::new().unwrap();let handle = runtime.localhost_handle();       runtime.block_on(async{let delay1 = handle.delay_from(Duration::from_secs(10));let delay2 = handle.delay_from(Duration::from_secs(30));let handle1 = handle.clone();let completed_at1 =crate::spawn_with_result(&handle1.clone(),asyncmove{               delay1.await;               handle1.now()}).await;let handle2 = handle.clone();let completed_at2 =crate::spawn_with_result(&handle2.clone(),asyncmove{               delay2.await;               handle2.now()}).await;assert!(completed_at1 < completed_at2)});}

Network

Simulation includes an in-memory network. Applications can useEnvironment::bind andEnvironment::connectto create in-memory connections between components. The in-memory connections will automatically have delaysand disconnect faults injected, dependent on an initial seed value.

[DeterministicRuntime] supports both a [DeterministicRuntime::localhost_handle] as well as creating a handlescoped to a particular [std::net:IpAddr] with [DeterministicRuntime::handle].

Faults

Faults are injected based on a seedable RNG, causing IO delays and disconnects.This is sufficient to trigger bugs in higher level components, such as message reordering.

By eliminating sources of nondeterminism, and basing fault injection on a seedable RNG, it'spossible to run many thousands of tests in the span of a few seconds with different faultinjections. This allows testing different execution orderings. If a particular seed causes afailing execution ordering, developers can use the seed value to debug and fix their applications.

Once the error is fixed, the seed value can be used to setup a regression test to ensure that theissue stays fixed.

Fault injection is handled by spawned tasks. Currently there is one fault injector which will injectdeterminstic latency changes to socket read/write sides based on the initial seed value passed to[DeterministicRuntime::new_with_seed]. Launching the fault injector involves spawning it at startup.

Example

The following example demonstrates a simple client server app which has latency faults injected.

use simulation::{Environment,TcpListener};use futures::{SinkExt,StreamExt};use std::{io, net, time};use tokio::codec::{Framed,LinesCodec};/// Start a client request handler which will write greetings to clients.asyncfnhandle<E>(env:E,socket: <E::TcpListenerasTcpListener>::Stream,addr: net::SocketAddr)whereE:Environment,{// delay the response, in deterministic mode this will immediately progress time.       env.delay_from(time::Duration::from_secs(1));println!("handling connection from {:?}", addr);letmut transport =Framed::new(socket,LinesCodec::new());ifletErr(e) = transport.send(String::from("Hello World!")).await{println!("failed to send response: {:?}", e);}}/// Start a server which will bind to the provided addr and repyl to clients.asyncfnserver<E>(env:E,addr: net::SocketAddr) ->Result<(), io::Error>whereE:Environment,{letmut listener = env.bind(addr).await?;whileletOk((socket, addr)) = listener.accept().await{let request =handle(env.clone(), socket, addr);           env.spawn(request)}Ok(())}/// Create a client which will read a message from the serverasyncfnclient<E>(env:E,addr: net::SocketAddr) ->Result<(), io::Error>whereE:Environment,{loop{match env.connect(addr).await{Err(_) =>{// Sleep if the connection was rejected, retrying later.// In deterministic mode, this will just reorder task execution// without waiting for time to advance.                   env.delay_from(time::Duration::from_secs(1)).await;continue;}Ok(conn) =>{letmut transport =Framed::new(conn,LinesCodec::new());let result = transport.next().await.unwrap().unwrap();assert_eq!(result,"Hello World!");returnOk(());}}}}#[test]fntest(){// Various seed values can be supplied to `DeterministicRuntime::new_with_seed` to find a seed// value for which this example terminates incorrectly.letmut runtime = simulation::deterministic::DeterministicRuntime::new_with_seed(1).unwrap();let handle = runtime.handle();       runtime.block_on(async{           handle.spawn(runtime.latency_fault().run());let bind_addr: net::SocketAddr ="127.0.0.1:8080".parse().unwrap();let server =server(handle.clone(), bind_addr);           handle.spawn(asyncmove{               server.await.unwrap();});client(handle, bind_addr).await.unwrap();})}

License: MIT

About

Framework for simulating distributed applications

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors3

  •  
  •  
  •  

Languages


[8]ページ先頭

©2009-2025 Movatter.jp