There are two thread pools:

  • Send http requests.
  • Process what came (for example, map from json to objects).

Main characters:

  1. RequestManager - has a push method (Request), which gives the currently free Request stream to be sent to the server.
  2. RequestSender (Runnable) - implements sending a request that came from RequestManager. The response from the server (HttpResponse) must be passed to the ResponseManager.
  3. ResponseManager - has a pool of handler threads and a push (HttResponse) method, which receives the response from the server as input and passes it to the free handler thread for processing.
  4. ResponseHandler (Runnable), accepts the next response from the server and sends it first to the preProcessor, which should have the basic error handling logic: the server was unavailable, sent a request in the wrong format, etc., if everything is ok, the handle () method is called which everyone can override depending on the task.

The point is this: during the execution, a lot of things can go "wrong". For example, there may be situations when the server returned only a part of the result (500 employees from 10,000) and asks to proceed by adding an offset to the query. In this case, the ResponseHandler should somehow retrieve the request that was made and send it to RequestManager with offset. But hell then this request will already process some other thread-handler from the pool, and I want to process it in one handler, sticking together all the answers. Another situation - the token that personifies the session orders to live long, which means one of the threads of the RequestManager pool, which is the carrier of this token and stitches it to all requests, will have to be killed. Therefore, again, RequestHandler should somehow get through to RequestManager and affect its operation. It has a bunch of cyclic dependencies. Hence the questions - how would you implement all this? Are there good patterns that are appropriate in this situation?

    1 answer 1

    You are in vain trying to bind a request to a stream.

    A request (or rather, all stages of its processing) must be represented by an object (a set of objects) that “travels” through the queues of your managers and must be completely independent of the data of a specific processing flow.

    For example, in this case, an incomplete request can be easily returned (with a new task in its body) to RequestManager (and further to RequestSender and then again ... to the desired handler).

    Actually, this approach is close to event driving (i.e., event management (and if you think about it, this is what it is)).