Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tips

Best Practices

  • When writing load tests, avoid unwrap() (and variations) in your transaction functions -- Goose generates a lot of load, and this tends to trigger errors. Embrace Rust's warnings and properly handle all possible errors, this will save you time debugging later.
  • When running your load test, use the cargo --release flag to generate optimized code. This can generate considerably more load test traffic. Learn more about this and other optimizations in "The golden Goose egg, a compile-time adventure".

Errors

Timeouts

By default, Goose will time out requests that take longer than 60 seconds to return, and display a WARN level message saying, "operation timed out". For example:

11:52:17 [WARN] "/node/3672": error sending request for url (http://apache/node/3672): operation timed out

These will also show up in the error summary displayed with the final metrics. For example:

 === ERRORS ===
 ------------------------------------------------------------------------------
 Count       | Error
 ------------------------------------------------------------------------------
 51            GET (Auth) comment form: error sending request (Auth) comment form: operation timed out

To change how long before requests time out, use --timeout VALUE when starting a load test, for example --timeout 30 will time out requests that take longer than 30 seconds to return. To configure the timeout programatically, use .set_default() to set GooseDefault::Timeout.

To completely disable timeouts, you must build a custom Reqwest Client with GooseUser::set_client_builder. Alternatively, you can just set a very high timeout, for example --timeout 86400 will let a request take up to 24 hours.

Debugging HTML Responses

Sometimes, while developing and debugging a load test we'd like to view HTML responses in a browser to actually see where each request is actually taking us. We may want to run this test with one user to avoid debug noise.

We can create a debug log by passing the --debug-log NAME command line option.

Each row in the debug log defaults to a JSON object and we can use jq for processing JSON or the faster Rust port that supports the same commands jaq

To extract the HTML response from the first log entry, for example, you could use the following commands:

cat debug.log | head -n 1 | jaq -r .body > page.html

This HTML page can then be viewed in a web browser. You may need to disable JavaScript.

Killswitch

Goose provides a killswitch mechanism to programmatically stop a load test when specific conditions are met. This is useful for protecting your systems and ensuring tests stop automatically when problems are detected.

Common Use Cases

  • Error Rate Threshold: Stop when error rate exceeds acceptable limits
  • Response Time SLA Monitoring: Halt testing when latency violates requirements
  • Health Check Integration: Monitor system health endpoints and stop on failure
  • Resource Exhaustion Detection: Stop when detecting connection pool or memory issues
  • Sitemap Traversal Completion: Stop after fully crawling a site's pages
  • Data Set Processing: Stop when all test data has been consumed
  • External Signal Integration: Stop based on monitoring system alerts

Example: Service Unavailable Detection

#![allow(unused)]
fn main() {
use goose::prelude::*;

async fn check_availability(user: &mut GooseUser) -> TransactionResult {
    let mut response = user.get("/api/endpoint").await?;
    
    // Stop the test if server returns 503 Service Unavailable
    if let Ok(response) = response.response {
        if response.status() == 503 {
            goose::trigger_killswitch("Server returned 503: Service Unavailable");
        }
    }
    
    Ok(())
}
}

You can also check if the killswitch has been triggered using goose::is_killswitch_triggered() to conditionally execute cleanup code or skip certain operations.