Package: async-reduce
About Async-Reduceasync_reduce(coroutine)allows aggregate allsimilar simultaneousready to runcoroutines and reduce to runningonly onecoroutine.
Other aggregatedcoroutines will get result from singlecoroutine.It can boost application performance in highly competitive execution of the
similar asynchronous operations and reduce load for inner systems.Quick examplefromasync_reduceimportasync_reduceasyncdeffetch_user_data(user_id:int)->dict:"""" Get user data from inner service """url='http://inner-service/user/{}'.format(user_id)returnawaithttp.get(url,timeout=10).json()@web_server.router('/users/(\d+)')asyncdefhandler_user_detail(request,user_id:int):""" Handler for get detail information about user """# all simultaneous requests of fetching user data for `user_id` will# reduced to single requestuser_data=awaitasync_reduce(fetch_user_data(user_id))# sometimes ``async_reduce`` cannot detect similar coroutines and# you should provide special argument `ident` for manually determinationuser_statistics=awaitasync_reduce(DataBase.query('user_statistics').where(id=user_id).fetch_one(),ident='db_user_statistics:{}'.format(user_id))returnResponse(...)In that example without usingasync_reduceif client performsNsimultaneous requests likeGET http://web_server/users/42web_serverperformsNrequests toinner-serviceandNqueries todatabase.
In total:Nsimultaneous requests emits2 * Nrequests to inner systems.Withasync_reduceif client performsNsimultaneous requestsweb_serverperformsonerequest toinner-serviceandonequery todatabase.
In total:Nsimultaneous requests emit only2requests to inner systems.See other realexamples.Similar coroutines determinationasync_reduce(coroutine)tries to detect similar coroutines by hashing
local variables bounded on call. It does not work correctly if:one of the arguments is not hashablecoroutine function is a method of class with specific state (like ORM)coroutine function has closure to unhashable variableYou can disable auto-determination by setting custom key to argumentident.Use as decoratorAlso library provide special decorator@async_reduceable(), example:fromasync_reduceimportasync_reduceable@async_reduceable()asyncdeffetch_user_data(user_id:int)->dict:"""" Get user data from inner service """url='http://inner-servicce/user/{}'.format(user_id)returnawaithttp.get(url,timeout=10).json()@web_server.router('/users/(\d+)')asyncdefhandler_user_detail(request,user_id:int):""" Handler for get detail information about user """returnawaitfetch_user_data(user_id)HooksLibrary supports hooks. Add-on hooks:DebugHooks- print about all triggered hooksStatisticsOverallHooks- general statistics on the use ofasync_reduceStatisticsDetailHooks- likeStatisticsOverallHooksbut detail statistics
about allcoroutineprocessed byasync_reduceExample:fromasync_reduceimportAsyncReducerfromasync_reduce.hooksimportDebugHooks# define custom async_reduce with hooksasync_reduce=AsyncReducer(hooks=DebugHooks())asyncdefhandler_user_detail(request,user_id:int):user_data=awaitasync_reduce(fetch_user_data(user_id))See more detail example inexamples/example_hooks.py.You can write custom hooks via inherit fromBaseHooks.CaveatsIf singlecoroutineraises exceptions all aggregatedcoroutines will get
same exception tooIf singlecoroutineis stuck all aggregatedcoroutines will stuck too.
Limit execution time forcoroutineand add retries (optional) to avoid it.Be careful when return mutable value fromcoroutinebecause single value
will shared. Prefer to use non-mutable value as coroutine return.DevelopmentSeeDEVELOPMENT.md.