This is an automated email from the ASF dual-hosted git repository.

hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin.git


The following commit(s) were added to refs/heads/master by this push:
     new 4e5626a  fix: notify watcher after transaction commit
4e5626a is described below

commit 4e5626ad398c90380ee9a2aa17da59cf649cb0f9
Author: Yang Luo <[email protected]>
AuthorDate: Tue Oct 20 21:08:27 2026 +0800

    fix: notify watcher after transaction commit
---
 transaction_commit.go | 34 ++++++++++++++++++++++++++++++++++
 transaction_test.go   | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 81 insertions(+)

diff --git a/transaction_commit.go b/transaction_commit.go
index b400c20..c2adc64 100644
--- a/transaction_commit.go
+++ b/transaction_commit.go
@@ -100,6 +100,40 @@ func (tx *Transaction) Commit() error {
        tx.committed = true
        tx.enforcer.activeTransactions.Delete(tx.id)
 
+       return tx.notifyWatcher()
+}
+
+// notifyWatcher tells other instances about the committed operations,
+// mirroring what the non-transactional management API does.
+func (tx *Transaction) notifyWatcher() error {
+       e := tx.enforcer
+       if !e.shouldNotify() {
+               return nil
+       }
+
+       watcherEx, isWatcherEx := e.watcher.(persist.WatcherEx)
+       updatableWatcher, isUpdatableWatcher := 
e.watcher.(persist.UpdatableWatcher)
+       if !isWatcherEx && !isUpdatableWatcher {
+               return e.watcher.Update()
+       }
+
+       for _, op := range tx.buffer.GetOperations() {
+               var err error
+               switch {
+               case op.Type == persist.OperationAdd && isWatcherEx:
+                       err = watcherEx.UpdateForAddPolicies(op.Section, 
op.PolicyType, op.Rules...)
+               case op.Type == persist.OperationRemove && isWatcherEx:
+                       err = watcherEx.UpdateForRemovePolicies(op.Section, 
op.PolicyType, op.Rules...)
+               case op.Type == persist.OperationUpdate && isUpdatableWatcher:
+                       err = 
updatableWatcher.UpdateForUpdatePolicies(op.Section, op.PolicyType, 
op.OldRules, op.Rules)
+               default:
+                       err = e.watcher.Update()
+               }
+               if err != nil {
+                       return err
+               }
+       }
+
        return nil
 }
 
diff --git a/transaction_test.go b/transaction_test.go
index 466d65c..ad0292d 100644
--- a/transaction_test.go
+++ b/transaction_test.go
@@ -576,3 +576,50 @@ func TestTransactionRemoveFilteredPolicyRollback(t 
*testing.T) {
                t.Fatal("The policy should still exist after a rollback")
        }
 }
+
+func TestTransactionCommitNotifiesWatcher(t *testing.T) {
+       adapter := NewMockTransactionalAdapter()
+       e, err := NewTransactionalEnforcer("examples/rbac_model.conf", adapter)
+       if err != nil {
+               t.Fatalf("Failed to create transactional enforcer: %v", err)
+       }
+       adapter.Enforcer = e.Enforcer
+
+       updates := 0
+       watcher := &SampleWatcher{}
+       if err := e.SetWatcher(watcher); err != nil {
+               t.Fatalf("Failed to set watcher: %v", err)
+       }
+       watcher.callback = func(string) { updates++ }
+
+       tx, err := e.BeginTransaction(context.Background())
+       if err != nil {
+               t.Fatalf("Failed to begin transaction: %v", err)
+       }
+       if _, err := tx.AddPolicy("alice", "data1", "read"); err != nil {
+               t.Fatalf("Failed to add policy in transaction: %v", err)
+       }
+       if updates != 0 {
+               t.Fatalf("Watcher should not be notified before commit, got %d 
updates", updates)
+       }
+       if err := tx.Commit(); err != nil {
+               t.Fatalf("Failed to commit transaction: %v", err)
+       }
+       if updates != 1 {
+               t.Fatalf("Watcher should be notified once after commit, got %d 
updates", updates)
+       }
+
+       tx, err = e.BeginTransaction(context.Background())
+       if err != nil {
+               t.Fatalf("Failed to begin transaction: %v", err)
+       }
+       if _, err := tx.RemovePolicy("alice", "data1", "read"); err != nil {
+               t.Fatalf("Failed to remove policy in transaction: %v", err)
+       }
+       if err := tx.Rollback(); err != nil {
+               t.Fatalf("Failed to roll back transaction: %v", err)
+       }
+       if updates != 1 {
+               t.Fatalf("Watcher should not be notified after rollback, got %d 
updates", updates)
+       }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to