Skip to main content

time-now-ns-twice

Summary: Repeated calls to time.now_ns

Category: Bugs

Avoid

package policy

timed if {
now := time.now_ns()

# do some work here

# this doesn't work! result is always 0
print("work done in:", time.now_ns() - now, "ns)
}

Prefer

To use the tools OPA provides for measuring performance.

Rationale

An important property of Rego is that it makes policy evaluation predictable. Using the same input to query OPA for a decision multiple times should result in the same decision being made each time! A few built-in functions, like http.send, or time.now_ns are however not deterministic. This means that repeated queries to policies where such functions are used may result in different decisions being made. For example, a policy that validates JSON Web Tokens would normally check if the current time is past the expiry value of the token, and deny any request where a token is found to be expired.

But while the use of non-deterministic built-in functions may result in different outcomes across different queries, all built-in functions are deterministic within the scope of a single evaluation. This means that calling e.g. http.send twice in a policy using the exact same arguments never results in different values being returned. This is equally true for time.now_ns. In order to ensure predictable evaluation, the time returned by time.now_ns is set once at the start of the evaluation, and never changes for the course of the request. Calling time.now_ns several times within a rule is thus pointless, as the same value will be returned each time.

This mistake is most commonly observed when developers try to measure elapsed time in some parts of their policy, the same way they'd normally do it using a traditional programming language (that is not deterministic). While this won't work, OPA provides several tools to help measure performance, and learning how to use them well is the best way to understand the performance characteristics of policy evaluation.

See the performance section of the OPA docs for an introduction to these tools, as well as advice on how to write performant policies.

Configuration Options

This linter rule provides the following configuration options:

rules:
bugs:
time-now-ns-twice:
# one of "error", "warning", "ignore"
level: error

Community

If you think you've found a problem with this rule or its documentation, would like to suggest improvements, new rules, or just talk about Regal in general, please join us in the #regal channel in the Styra Community Slack!