Performance Considerations
Guantr is designed to be flexible and powerful, but like any system component, its performance can be influenced by various factors, especially under load. Understanding these factors can help you optimize your Guantr setup for demanding applications.
Factors Affecting Performance
Several key areas contribute to the overall performance of Guantr's permission checks (can
/cannot
calls):
Number of Rules:
- Impact: The total number of rules stored can affect the performance of
queryRules
(fetching relevant rules) and potentially the number of rules Guantr needs to iterate through during evaluation. - Details: While Guantr attempts to fetch only relevant rules via
storage.queryRules(action, resource)
, if that method is inefficient (see Storage Adapter below) or if many rules match a specific action/resource pair, processing time can increase.
- Impact: The total number of rules stored can affect the performance of
Complexity of Conditions:
- Impact: The structure and operators used within your rule
condition
objects directly impact CPU usage during evaluation. - Details: Evaluating simple equality checks (
['eq', value]
) is very fast. However, more complex operations like string matching (contains
,startsWith
,endsWith
), numerical comparisons (gt
,gte
), or especially array operations (in
,has
,hasSome
,hasEvery
) require more computation. Nested conditions and operators likesome
,every
,none
that iterate over arrays of objects can be significantly more CPU-intensive, especially with large arrays.
- Impact: The structure and operators used within your rule
getContext
Speed:- Impact: The time taken by your
getContext
function directly adds latency to any permission check that uses$ctx
operands. - Details: If
getContext
performs slow operations like database queries, external API calls, or complex computations every time it's called, this can become a major bottleneck. As discussed in the Using Context Effectively guide, this function might be called whenever a context-dependent rule is evaluated (though internal caching might reduce redundant calls for the same check).
- Impact: The time taken by your
Storage Adapter Choice &
queryRules
Efficiency:- Impact: Both the underlying storage technology (in-memory, Redis, PostgreSQL, etc.) and the implementation quality of the storage adapter significantly affect performance.
- Details:
- Latency: Accessing
InMemoryStorage
is extremely fast. Network latency affects Redis/remote DBs. Disk I/O affects local databases like SQLite. queryRules
Implementation: This is CRITICAL. TheStorage
interface requires aqueryRules(action, resource)
method. Adapters that efficiently filter rules at the data source (e.g., using SQLWHERE
clauses with database indexes, like the SQLite and Prisma examples) will vastly outperform adapters that fetch all rules and filter them in application memory (like the basic LocalStorage and Redis examples) when dealing with a large total number of rules.
- Latency: Accessing
Caching Effectiveness:
- Impact: The optional caching layer (
storage.cache
) can significantly reduce latency for repeated checks or context resolutions. - Details: An effective cache (good hit rate, fast backend like Redis or in-memory Map) mitigates the cost of re-running
can
/cannot
logic or re-resolving$ctx
operands for identical inputs. However, caching adds its own overhead (checking the cache, serialization) and requires careful consideration of invalidation. See the Caching Guide.
- Impact: The optional caching layer (
Optimization Tips
Based on the factors above, here are tips for optimizing Guantr performance:
Optimize Rule Definitions:
- Keep Conditions Simple: For frequently checked permissions, use the simplest possible conditions. Avoid complex array operations (
some
,every
, etc.) on large data sets within conditions if possible. - Minimize Rule Count (Selectively): While Guantr aims to query only relevant rules, reducing the total number of rules can help, especially if your
queryRules
implementation isn't highly optimized. Consolidate rules where logical. - Leverage
deny
: Use specificdeny
rules to restrict access rather than overly complex negative conditions inallow
rules.
- Keep Conditions Simple: For frequently checked permissions, use the simplest possible conditions. Avoid complex array operations (
Optimize
getContext
:- Fetch Data Once: In web frameworks, fetch user/session data once per request (e.g., in auth middleware) and have
getContext
simply return this pre-fetched object. Avoid database calls or heavy computation insidegetContext
. - Keep Context Small: Only include data in the context object that is actually needed for rule evaluation.
- Fetch Data Once: In web frameworks, fetch user/session data once per request (e.g., in auth middleware) and have
Optimize Storage:
- Choose Appropriate Adapter: Select a storage backend suitable for your scale and persistence needs (e.g.,
InMemoryStorage
for transient rules, Redis for shared cache/rules, a database for robust persistence). - Implement
queryRules
Efficiently: If using a custom or database adapter, ensurequeryRules(action, resource)
filters data at the source using appropriate indexes (e.g., a database index onaction
andresource
columns). Avoid loading all rules into memory for filtering.
- Choose Appropriate Adapter: Select a storage backend suitable for your scale and persistence needs (e.g.,
Utilize Caching:
- Enable Caching: Implement the
storage.cache
interface, especially ifgetContext
performs I/O or if the same permission checks are common. - Choose Fast Backend: Use an efficient cache backend (in-memory Map for single instance, Redis/Memcached for distributed).
- Consider Invalidation: Ensure your caching strategy includes appropriate invalidation (e.g., clear cache when rules change via
setRules
).
- Enable Caching: Implement the
Profile:
- Measure performance in your specific application under realistic load. Identify bottlenecks using profiling tools to focus your optimization efforts where they matter most.
Conclusion
Guantr's performance depends on a combination of factors related to rule definition, context handling, storage interaction, and caching. By understanding these elements and applying targeted optimizations—particularly ensuring efficient getContext
calls and an optimized queryRules
implementation in your storage adapter—you can ensure Guantr runs efficiently even in demanding scenarios.