Package: casbin-async-redis-watcher
casbin_async_redis_watcherasync casbin redis watcherasync-redis-watcherasync-redis-watcher is theRediswatcher forpycasbin. With this library, Casbin can synchronize the policy with the database in multiple enforcer instances.what is redis-watcher's problem?When use web framework like FastApi, the event loop run in main thread, but redis-watcher start a new Thread for monitor policy change and synchronize the policy .So when use sqlalchemy as AsyncEnforcer,  because there has two loop in diff threaddefnew_watcher(option:WatcherOptions):option.init_config()w=RedisWatcher()rds=Redis(host=option.host,port=option.port,password=option.password,ssl=option.ssl)ifrds.ping()isFalse:raiseException("Redis server is not available.")w.sub_client=rds.client().pubsub()w.pub_client=rds.client()w.init_config(option)w.close=Falsew.subscribe_thread.start()w.subscribe_event.wait(timeout=5)returnwIt usew.subscribe_thread.start()to start a new thread, This can lead to a lot of mistakes!You will see the follow errorcb=[_run_until_complete_cb() at C:\Python310\lib\asyncio\base_events.py:184]> got Future <Future pending> attached to a different loopI modified the redis-watcher to async-redis-watcher, Solve these problems once and for all and support asynchronous calls.Installationpip install casbin_async_redis_watcherSimple Exampleimportasyncioimportosimportcasbinfromcasbin_async_redis_watcherimportnew_watcher,WatcherOptionsfromcasbinimportAsyncEnforcerfromfunctoolsimportpartialasyncdefupdate_policy(e:AsyncEnforcer,event):print("receive a new update policy....")print(event)awaite.load_policy()defget_examples(path):examples_path=os.path.split(os.path.realpath(__file__))[0]+"/../examples/"returnos.path.abspath(examples_path+path)asyncdefmake_async_casbin_watcher():test_option=WatcherOptions()test_option.host="localhost"test_option.port="6379"test_option.password="password"test_option.channel="test"test_option.db=4test_option.ssl=Falsee=casbin.AsyncEnforcer(get_examples("rbac_model.conf"),get_examples("rbac_policy.csv"))func=partial(update_policy,e)test_option.optional_update_callback=funcwatcher=awaitnew_watcher(test_option)e.set_watcher(watcher)awaite.load_policy()returneasyncdefmain():e=awaitmake_async_casbin_watcher()awaite.save_policy()awaitasyncio.sleep(2)awaite.add_role_for_user("yangyanxing","admin")if__name__=="__main__":loop=asyncio.get_event_loop()loop.run_until_complete(main())loop.run_forever()In pycasbin,casbin/async_internal_enforcer.pyline 114,asyncdef_add_policy(self,sec,ptype,rule):"""async adds a rule to the current policy."""rule_added=self.model.add_policy(sec,ptype,rule)ifnotrule_added:returnrule_addedifself.adapterandself.auto_save:result=awaitself.adapter.add_policy(sec,ptype,rule)ifresultisFalse:returnFalseifself.watcherandself.auto_notify_watcher:ifcallable(getattr(self.watcher,"update_for_add_policy",None)):self.watcher.update_for_add_policy(sec,ptype,rule)else:self.watcher.update()returnrule_addedWhen call _add_policy function,_add_policies,save_policy and so on, if set watcher, will callwatcher.update_for_add_policyorwatcher.update()function.But it's NOT use await, so, in this project, watcher.py, class RedisWatcher, the functionupdatecan't use async.so I use loop.create_task for call the update functiondefupdate(self):asyncdeffunc():asyncwithself.mutex:msg=MSG("Update",self.options.local_ID,"","","")returnawaitself.pub_client.publish(self.options.channel,msg.marshal_binary())returnself.loop.create_task(self.log_record(func))Getting HelppycasbinLicenseThis project is under Apache 2.0 License. See theLICENSEfile for the full license text.