Skip to content

feat!: Ability to limit policy evaluation time#539

Merged
anakrish merged 1 commit intomicrosoft:mainfrom
anakrish:execution-limits
Jan 28, 2026
Merged

feat!: Ability to limit policy evaluation time#539
anakrish merged 1 commit intomicrosoft:mainfrom
anakrish:execution-limits

Conversation

@anakrish
Copy link
Copy Markdown
Collaborator

@anakrish anakrish commented Jan 8, 2026

  • Introduce ExecutionTimer/ExecutionTimerConfig to allow limiting evaluating time.
  • To amortize time checking costs, checking interval can be configured via the notion of work units
  • A global fallback time limit can be set to universally limit all evaluation in addition to engine level limit setting.
  • Implement limnits in interpreter and RVM. In RVM, also handle suspend/resume so that time during pause is not counted.
  • Add engine-level APIs to set/clear per-engine timer configuration and apply global fallback defaults.
  • Surface execution-time limits through FFI and C# bindings
  • Add C# tests and example usage to validate engine overrides, global fallback behavior, and compiled policy enforcement.
  • Expand docs for execution-time limit
  • Add interpreter YAML cases and VM unit tests for time-limit behavior and deterministic time sources.

@anakrish anakrish force-pushed the execution-limits branch 2 times, most recently from 4657e46 to 28ad239 Compare January 9, 2026 02:58
@anakrish anakrish force-pushed the execution-limits branch 3 times, most recently from 6233f35 to 9f21f1d Compare January 27, 2026 10:49
…inding

- Introduce ExecutionTimer/ExecutionTimerConfig to allow limiting evaluating time.
- To amortize time checking costs, checking interval can be configured via the notion of work units
- A global fallback time limit can be set to universally limit all evaluation in addition to engine level limit setting.
- Implement limnits in interpreter and RVM. In RVM, also handle suspend/resume so that time during pause is not counted.
- Add engine-level APIs to set/clear per-engine timer configuration and apply global fallback defaults.
- Surface execution-time limits through FFI and C# bindings
- Add C# tests and example usage to validate engine overrides, global fallback behavior, and compiled policy enforcement.
- Expand docs for execution-time limit
- Add interpreter YAML cases and VM unit tests for time-limit behavior and deterministic time sources.

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
@anakrish anakrish marked this pull request as ready for review January 27, 2026 13:35
action(handlePtr);
return null;
});
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I don't know how hot is this code path but we are boxing null as object?. We could instead copy/paste the UseHandle method without the return:

private void UseHandle(Action<IntPtr> action)
{
    var handle = GetHandleForUse();
    bool addedRef = false;
    try
    {
        handle.DangerousAddRef(ref addedRef);
        var pointer = handle.DangerousGetHandle();
        if (pointer == IntPtr.Zero)
        {
            throw new ObjectDisposedException(nameof(CompiledPolicy));
        }

        action(pointer);
    }
    finally
    {
        if (addedRef)
        {
            handle.DangerousRelease();
        }
    }
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative option would be to refactor the handle handling :-) logic to a separate method and call it from both:

private T UseHandle<T>(Func<IntPtr, T> func)
{
    T? result = default!;
    WithHandle(ptr => result = func(ptr));
    return result!;
}

private void UseHandle(Action<IntPtr> action)
{
    WithHandle(action);
}

private void WithHandle(Action<IntPtr> body)
{
    var handle = GetHandleForUse();
    bool addedRef = false;
    try
    {
        handle.DangerousAddRef(ref addedRef);
        var pointer = handle.DangerousGetHandle();
        if (pointer == IntPtr.Zero)
        {
            throw new ObjectDisposedException(nameof(CompiledPolicy));
        }

        body(pointer);
    }
    finally
    {
        if (addedRef)
        {
            handle.DangerousRelease();
        }
    }
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created #554 to track this. There is one C# specific PR remaining (expose VM to C#) that will wrap up the recent stream of work to improve robustness at Azure scale (super strict clippy lints, memory limits, executions limits). I will address this along with that.

Copy link
Copy Markdown

@dpokluda dpokluda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@anakrish anakrish mentioned this pull request Jan 28, 2026
@anakrish anakrish merged commit 394625d into microsoft:main Jan 28, 2026
41 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants