Skip to content

Query Timeout Protection - Quick Reference

What is it?

Query timeout protection prevents resource exhaustion by automatically terminating queries that run longer than a configured time limit.

Quick Start

Enable Timeout

use heliosdb_nano::{EmbeddedDatabase, Config};
let mut config = Config::default();
config.storage.query_timeout_ms = Some(30000); // 30 seconds
let db = EmbeddedDatabase::new_with_config(config)?;

Handle Timeout Errors

use heliosdb_nano::Error;
match db.query("SELECT * FROM large_table") {
Err(Error::QueryTimeout(msg)) => {
println!("Query timed out: {}", msg);
// Handle timeout
}
Ok(results) => {
println!("Success: {} rows", results.len());
}
Err(e) => {
println!("Error: {}", e);
}
}

Configuration

Via Config File (TOML)

[storage]
query_timeout_ms = 30000 # 30 seconds (recommended for production)

Via Code

// Set timeout
config.storage.query_timeout_ms = Some(5000); // 5 seconds
// Disable timeout
config.storage.query_timeout_ms = None; // Unlimited (default)
EnvironmentTimeoutNotes
DevelopmentNone or 60000Unlimited or 60s for debugging
Production3000030 seconds is a good default
Public API1000010 seconds for user-facing queries
Background Jobs3000005 minutes for batch processing
Admin ToolsNoneUnlimited for maintenance operations

Error Message Format

Query timeout: Query exceeded timeout limit of 5000ms (elapsed: 5124ms)

Key Features

  • Zero-config compatibility: Disabled by default
  • Minimal overhead: <0.1% performance impact
  • Thread-safe: Works with parallel execution
  • Granular control: Configurable per database instance

Performance Impact

Check FrequencyOverheadCurrent Setting
Every 1000 rows<0.1%✓ Default

Limitations

  1. Granularity: Checked every 1000 rows, not every row
  2. DDL Operations: Not protected (CREATE TABLE, etc.)
  3. Blocking I/O: Timeout suspended during I/O operations

Common Use Cases

Prevent Runaway Queries

// Prevent expensive queries from running forever
config.storage.query_timeout_ms = Some(30000);

Different Timeouts for Different Environments

let timeout = if cfg!(debug_assertions) {
None // Unlimited in development
} else {
Some(30000) // 30 seconds in production
};
config.storage.query_timeout_ms = timeout;

Graceful Degradation

match db.query(complex_query) {
Err(Error::QueryTimeout(_)) => {
// Fall back to simpler query
db.query(simple_query)?
}
result => result,
}

Troubleshooting

Query Always Timing Out

Problem: Legitimate queries are timing out

Solution:

  1. Increase timeout: query_timeout_ms = Some(60000) (60s)
  2. Optimize query (add indexes, reduce data scanned)
  3. Use LIMIT to reduce result set size

No Timeout Protection

Problem: Long queries still running

Solution:

  1. Verify configuration: config.storage.query_timeout_ms.is_some()
  2. Check error handling catches Error::QueryTimeout
  3. Ensure database created with updated config

Timeout Too Strict

Problem: Complex analytical queries failing

Solution:

  1. Increase timeout for specific workloads
  2. Use batch processing for large operations
  3. Consider disabling timeout for admin operations

Enabling a Timeout in Existing Code

No breaking changes.

Timeout is disabled by default. To enable:

// Without a timeout (the default)
let db = EmbeddedDatabase::new()?;
// With a 30-second timeout
let mut config = Config::default();
config.storage.query_timeout_ms = Some(30000);
let db = EmbeddedDatabase::new_with_config(config)?;

Security Best Practices

✓ Enable timeout in production ✓ Set conservative limits for public APIs ✓ Monitor timeout frequency ✓ Log timeout events

Further Reading

Summary

Query timeout protection provides:

  • Protection against resource exhaustion
  • Minimal performance overhead (<0.1%)
  • Easy configuration (one line)
  • Backward compatible (disabled by default)
  • operationally hardened security enhancement

Recommended Action: Enable with 30 second timeout for all production deployments.