Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 28, 2025

In distributed microservice architectures using watchers with autoSave=true, updating local policies from watcher callbacks currently creates duplicate database entries and triggers infinite notification loops. The existing self* methods still call the adapter when autoSave is enabled.

Changes

  • Internal methods: Added useAdapter parameter (default: true) to all *Internal() methods in InternalEnforcer to control adapter invocation independently from autoSave setting

  • Self methods: Updated selfAddPolicy(), selfRemovePolicy(), selfUpdatePolicy(), selfAddPolicies(), selfRemovePolicies(), and selfRemoveFilteredPolicy() in ManagementEnforcer to pass useAdapter: false, ensuring they bypass both adapter and watcher

  • Documentation: Added JSDoc explaining these methods are for in-memory updates in distributed setups

Usage

// Watcher callback in microservices B, C, etc.
watcher.setUpdateCallback(async () => {
  const changeEvent = getChangeFromMongoDB(); // e.g., policy added
  
  // Update local enforcer without saving to DB or notifying watcher
  await enforcer.selfAddPolicy('p', 'p', changeEvent.newPolicy);
});

Backward compatible - default parameter values preserve existing behavior.

Original prompt

This section details on the original issue you should resolve

<issue_title>Feature request: Methods in enforcer for adding, updating and deleting policies without usage of adapter (even if autoSave is true)</issue_title>
<issue_description>My environment/setup:

  • Microservice architecture
  • using casbin with casbin-mongoose-adapter (SyncedAdapter) and @casbin/mongo-changestream-watcher
  • autoSave is true

For my use case I need methods in the enforcer for adding, updating and deleting policies only inside the enforcer object itself - even if an adapter is set and autoSave is true.

I need these functions, to be able to call them in the updateCallback of the watcher of all microservices, because I need the watcher to keep the policy up to date across all microservices. With the currently available methods its not possible to do this without any performance issues or creating duplicates of policies in the MongoDB collection.

This issue results out of a PR (#505) for discussion.

The methods, that I added, are for me for calling inside the updateCallback() of the watcher.

Here is a detailed example to better understand my problem:

Lets say we got three microservices (A, B and C), all three can interact with the casbin policy (reading, adding, updating, deleting policies).

Microservice A adds a new policy via enforcer.addPolicy(). This leads to a new document in the MongoDB collection and that creates a change event on the MongoDB change stream.

So the updateCallback function of the watcher in all three microservices is called. In this function I could just reload the whole policy via enforcer.loadPolicy(). This would work! BUT that is performance wise a bad idea if we got severval hundred microservices doing that all the time.
So in the updateCallback function of all three microservices I check instead first:

  • is the newly added policy already part of the policy of the enforcer?
    • in microservice A it is already part of the policy, so we don't do anything further
    • in microservice B and C the newly added policy is not part of the policy:
      • I call enforcer.addPolicy() to add it to the policy of the enforcer of microservice B and C. But enforcer.addPolicy() also adds the policy via the adapter by calling adapter.addPolicy(). So at this point I am creating duplicates of the new policy in the MongoDB colleciton. And enforcer.addPolicy() also calls the watcher.update() again which is just unnecessary but causing no issues.

So I wanted a method for adding policies, that does not call adapter.addPolicy() and also does not call watcher.update(). The same for updating and deleting policies. So what I need are functions like selfAddPolicy(), selfRemovePolicy(), and so on that not only don't call watcher.update() but also don't call the adapter functions on policy changes.

I hope it makes sense, why I want these new methods? Or am I missing something and my approach does not make any sense?

</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copilot AI and others added 3 commits December 28, 2025 11:20
Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com>
Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com>
Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com>
Copilot AI changed the title [WIP] Add methods in enforcer for policy management Add self* policy methods to bypass adapter and watcher in distributed setups Dec 28, 2025
Copilot AI requested a review from hsluoyz December 28, 2025 11:25
@hsluoyz hsluoyz marked this pull request as ready for review December 28, 2025 11:34
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.

Feature request: Methods in enforcer for adding, updating and deleting policies without usage of adapter (even if autoSave is true)

3 participants