The current asyncore based ZServer allows fun asynchronous features, which I have been relying a lot (collective.zamqp integrates Plone with RabbitMQ, collective.taskqueue runs simpler worker queue next to Plone without extra services and collective.futures frees Zope worker thread to server other requests while eg. waiting for a response for external service). Many may also still rely on Zope clockserver.
Obviously non of the above work with WSGI, which is fully synchronous in nature, so I should start planning replacements
Normal WSGI does not support anything async, so the only pure option probably is a middleware, which queues tasks for external workers after successful transaction. If worker need ZODB access, it probably needs to call Plone using restapi and its authentication.
Using some non-standard asynchronous WSGI server would allow async operations in middle-ware, but would require choosing the server and async solution and possible locking into some specific server (eg. uwsgi or unicorn).
Finally, there’s an option to implement ZServer on top of asyncio
This is probably the simplest solution, and should work with any WSGI server with a simple queuing middleware. Passing JWT for the user triggering the task should be enough for most use cases (to avoid managing special secrets for the workers), with some exception handling for those rare cases where JWT gets expired before the worker has execute the task
And this is how the current ZServer works. The benefit for having async worker in the same async loop with ZServer is that it could intercept responses and "hold" it until some async task have been completed. This is how collective.futures work (as long as there are unsolved futures, it will retry the request internally while browser remains waiting).
This would be most work for these options (aiohttp could replace medusa, thread executor could replace ZRendevouz, but a lot of work remains to adapt to Zope request, response, querystring demarshalling, etc...), but would allow very fancy stuff with aiohttp middlewares before and after ZPublisher.
Also, this allows async tasks to call Plone views, which are not visible for regular HTTP requests. I don't claim it's more secure than having HTTP calls to public views with proper token authentication, but it is a bit simpler for trusted code.
That was the second option in the first post, still under consideration, but as you said, it's "short of" and requires playing with gevent/greenlets. In my understanding async WSGI would require lock-in to a specific WSGI server (gunicorn, uwsgi, pulsar...). That makes it hard to see benefits over aiohttp based ZServer (besides a little less work).
And I am sorry that I cannot update that to WSGI based Plone. collective.taskqueue does have a branch that works with my ZServer branch on Python 3 and Plone 5.2.x. I have been running Python 3 ZServer with Plone 5.2.1 in production about a year now, but have not been using collective.taskqueue in those projects yet (but much more heavy Camunda + microservices + Plone REST API setup instead due to their requirements). That said, @gforcada has been interested in trying out ZServer with c.taskqueue + Redis...
c.taskqueue Python 3 branch works with my ZServer branch with or without Redis; the issue is that I have not been able to do and maintain released versions of those (not mentioning plone.recipe.zope2instance-support, which has no ZServer support on Python 3)