Overriding Workers

You can override the code run by each uWSGI worker thanks to the “worker” hook exposed to plugins.

Currently the python plugin is the only one exposing it:

  1. [uwsgi]
  2. ; create a bunch of sockets
  3. socket = 127.0.0.1:3031
  4. socket = 127.0.0.1:3032
  5. ; spawn the master
  6. master = true
  7. ; spawn 4 processes
  8. processes = 4
  9. ; load a python script as the worker code
  10. python-worker-override = aioserver.py

The python script has access to the uwsgi module so it can control/change its internals.

The following examples shows the use of aiohttp (requires python 3.5)

  1. import asyncio
  2. from aiohttp import web
  3.  
  4. import uwsgi
  5. import socket
  6. import sys
  7. import signal
  8.  
  9. async def handle(request):
  10. name = request.match_info.get('name', "Anonymous")
  11. text = "Hello, " + name
  12. return web.Response(body=text.encode('utf-8'))
  13.  
  14. async def wshandler(request):
  15. ws = web.WebSocketResponse()
  16. await ws.prepare(request)
  17.  
  18. async for msg in ws:
  19. if msg.tp == web.MsgType.text:
  20. ws.send_str("Hello, {}".format(msg.data))
  21. elif msg.tp == web.MsgType.binary:
  22. ws.send_bytes(msg.data)
  23. elif msg.tp == web.MsgType.close:
  24. break
  25.  
  26. return ws
  27.  
  28. async def init(loop, fd):
  29. app = web.Application(loop=loop)
  30. app.router.add_route('GET', '/echo', wshandler)
  31. app.router.add_route('GET', '/{name}', handle)
  32.  
  33. srv = await loop.create_server(app.make_handler(),
  34. sock=socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM))
  35. print("asyncio server started on uWSGI {0}".format(uwsgi.version))
  36. return srv
  37.  
  38. def destroy():
  39. print("destroy worker {0}".format(uwsgi.worker_id()))
  40. sys.exit(0)
  41.  
  42. def graceful_reload():
  43. print("graceful reload for worker {0}".format(uwsgi.worker_id()))
  44. # TODO do somethign meaningful
  45. sys.exit(0)
  46.  
  47. loop = asyncio.get_event_loop()
  48. loop.add_signal_handler(signal.SIGINT, destroy)
  49. loop.add_signal_handler(signal.SIGHUP, graceful_reload)
  50. # spawn a handler for every uWSGI socket
  51. for fd in uwsgi.sockets:
  52. loop.run_until_complete(init(loop, fd))
  53. uwsgi.accepting()
  54. loop.run_forever()

In the example (taken from the official aiohttp docs) we see the uwsgi.sockets list (holding the list of uWSGI sockets file descriptors), and the override of SIGINT and SIGHUP to support reloading (SIGHUP should be adapted to support waiting for all the queued requests)

uwsgi.accepting() is called to notify the master that the worker is accepting requests, this is required for touch-chain-reload to work.

The script should be extended to call uwsgi.log(…) after every request and to (eventually) update some metrics