This repository has been archived on 2025-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
rhaj/_archive/rhai_engine/rhaibook/safety/progress.md
2025-04-04 08:28:07 +02:00

3.0 KiB

Limiting Run Time

Track Progress and Force-Termination

{{#include ../links.md}}


_Operations count_ does not indicate the _proportion_ of work already done – thus it is not real _progress_ tracking.

The real progress can be _estimated_ based on the expected number of operations in a typical run.

It is impossible to know when, or even whether, a script run will end (a.k.a. the Halting Problem).

When dealing with third-party untrusted scripts that may be malicious, in order to track evaluation progress and force-terminate a script prematurely (for any reason), provide a closure to the [Engine] via Engine::on_progress.

The closure passed to Engine::on_progress will be called once for every operation.

Progress tracking is disabled with the [unchecked] feature.

Examples

Periodic Logging

let mut engine = Engine::new();

engine.on_progress(|count| {    // parameter is number of operations already performed
    if count % 1000 == 0 {
        println!("{count}");    // print out a progress log every 1,000 operations
    }
    None                        // return 'None' to continue running the script
                                // return 'Some(token)' to immediately terminate the script
});

Limit running time

let mut engine = Engine::new();

let start = get_time();         // get the current system time

engine.on_progress(move |_| {
    let now = get_time();

    if now.duration_since(start).as_secs() > 60 {
        // Return a dummy token just to force-terminate the script
        // after running for more than 60 seconds!
        Some(Dynamic::UNIT)
    } else {
        // Continue
        None
    }
});

Function Signature of Callback

The signature of the closure to pass to Engine::on_progress is as follows.

Fn(operations: u64) -> Option<Dynamic>

Return value

Value Effect
Some(token) terminate immediately, with token (a [Dynamic] value) as termination token
None continue script evaluation

Termination Token


The termination token is commonly used to provide information on the _reason_ behind the termination decision.

The [Dynamic] value returned is a termination token.

A script that is manually terminated returns with the error EvalAltResult::ErrorTerminated(token, position) wrapping this value.

If the termination token is not needed, simply return Some(Dynamic::UNIT) to terminate the script run with [()] as the token.