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]