Package: servitin
AboutThis package provides services for django applications. The servitin service is an asynchronous standalone application.InstallationpipinstallservitinHowtoAddservitintosettings.INSTALLED_APPSMake sure you haveLOGGINGsettings in your project - servitin needs this.Let's say you have a django appmyapp.Makemyappa servitin service by adding the lineis_servitin = Trueinmyapp/apps.py:fromdjango.appsimportAppConfigclassMyappConfig(AppConfig):default_auto_field='django.db.models.BigAutoField'name='myapp'is_servitin=TrueCreate filemyapp/servitin.py:fromservitin.baseimportBaseServiceclassService(BaseService):def__init__(self,*args,**kwargs):super().__init__(*args,**kwargs)self.log.info(f"Myapp service ready.")(Not necessary) Give the versionmyapp, write in the filemyapp/__init__.py:__version__='1.0'Start service:./manage.pyrun_servitinIf all is ok you will see in the logMyapp service ready.LoggingTo configure the built-in logger for each service, Servitin looks for a logger namedservitin_myservice_loggerfor themyserviceapp,
similarly for themy_other_serviceapp it will look forservitin_my_other_service_logger.Buil-in logger is used like this:self.log.info(f"Myapp service ready.")in the example aboveRequest handlingEditmyapp/servitin.pyto make the service as the ZeroMQ server:fromservitin.baseimportBaseServicefromservitin.lib.zmq.serverimportZMQServerclassService(ZMQServer,BaseService):def__init__(self,*args,**kwargs):super().__init__(*args,**kwargs)self.log.info(f"Myapp service ready.")Createmyapp/settings.py:fromdjango.confimportsettingssettings.SERVITIN_MYAPP_ZMQ=getattr(settings,'SERVITIN_MYAPP_ZMQ',{'BIND_ADDRESS':'tcp://*:5555','CONNECT_ADDRESS':'tcp://127.0.0.1:5555','SECRET':''})Create filemyapp/zmq.py:importasynciofromservitin.lib.zmq.serverimportzmq,Responsefromasgiref.syncimportsync_to_asyncfromdjango.coreimportserializersfromdjango.contrib.auth.modelsimportUserfromservitin.utilsimportserializable@zmqasyncdefget_users(request):order_by=request.data['order_by']# use built-in loggerrequest.log.info(f'request order:{order_by}',name='@get_users')defget_data():# data with datetime objects, so it no serializabledata=serializers.serialize('python',User.objects.all().order_by(order_by),fields=('username','date_joined'))# so make it serializable (you can use your own serializer)returnserializable(data)returnResponse(request,awaitsync_to_async(get_data)())@zmqasyncdefheavy_task(request):""" emulate heavy task endpoint for timeout test """awaitasyncio.sleep(5)request.log.info(f'data:{request.data}',id=request.request_id,name='@heavy_task')returnResponse(request,f'complete:{request.data}')Here we have created two endpoints:get_users,heavy_task.
The service is ready to handle requests, let's test it.Create django management commandmyapp/management/commands/test_myapp_service.py:importasynciofromdjango.core.managementimportBaseCommandfromservitin.lib.zmq.clientimportServitinimportmyapp.settings# import our service settingsclassCommand(BaseCommand):defhandle(self,*args,**options):asyncdefdo():asyncwithServitin('myapp').connect()asmy_service:print(awaitmy_service.get_users({'order_by':'username'}))asyncio.run(do())In this example servitin client configured viamyapp/settings.py.Run it:./manage.pytest_myapp_serviceCallsIt is also possible to use the servitin client outside of django.Create filetest_calls.py:fromservitin.lib.zmq.clientimportServitinimportasyncioloop=asyncio.get_event_loop()params={'connect':'tcp://127.0.0.1:5555','secret':''}# ASYNC CALLSasyncdefdo():# manual close connectionmy_service=Servitin(**params)results=awaitasyncio.gather(*[my_service.get_users({'order_by':'username'}),my_service.get_users({'order_by':'id'})])print(results)my_service.close()# close connection# auto close connection via context managerasyncwithServitin(**params).connect()asmy_service:print(awaitmy_service.get_users({'order_by':'username'}))# timeout# you can specify timeout by passing it to Servitin():# async with Servitin(connect='tcp://127.0.0.1:5555', secret='', timeout=1).connect() as my_service:asyncwithServitin(**params).connect()asmy_service:try:# or pass it directly in callprint(awaitmy_service.heavy_task({'data':'context manager, timeout call'},timeout=1))exceptasyncio.TimeoutErrorase:print(e.__repr__())loop.run_until_complete(do())# SYNC CALLSparams={'connect':'tcp://127.0.0.1:5555','secret':'','async_mode':False}# manualmy_service=Servitin(**params)print(my_service.get_users({'order_by':'username'}))my_service.close()# via context managerwithServitin(**params).sync_connect()asmy_service:print(my_service.get_users({'order_by':'username'}))loop.close()