docs: @GET
    @Produces({MediaType.APPLICATION_JSON, SmileMediaTypes.APPLICATION_JACKSON_SMILE})
    public void getWorkerState(
        @QueryParam("counter") long counter,
        @QueryParam("hash") long hash,
        @QueryParam("timeout") long timeout,
        @Context final HttpServletRequest req
    ) throws IOException
    {
      if (timeout <= 0) {
        sendErrorResponse(req, HttpServletResponse.SC_BAD_REQUEST, "timeout must be positive.");
        return;
      }
  
      final ResponseContext context = createContext(req.getHeader("Accept"));
  
      final ListenableFuture<ChangeRequestsSnapshot<WorkerHistoryItem>> future = workerTaskMonitor.getChangesSince(
          new ChangeRequestHistory.Counter(
              counter,
              hash
          )
      );
  
      final AsyncContext asyncContext = req.startAsync();
  
      asyncContext.addListener(
          new AsyncListener()
          {
            @Override
            public void onComplete(AsyncEvent event)
            {
            }
  
            @Override
            public void onTimeout(AsyncEvent event)
            {
  
              // HTTP 204 NO_CONTENT is sent to the client.
              future.cancel(true);
              event.getAsyncContext().complete();
            }
  
            @Override
            public void onError(AsyncEvent event)
            {
            }
  
            @Override
            public void onStartAsync(AsyncEvent event)
            {
            }
          }
      );
  
      Futures.addCallback(
          future,
          new FutureCallback<ChangeRequestsSnapshot>()
          {
            @Override
            public void onSuccess(ChangeRequestsSnapshot result)
            {
              try {
                HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse();
                response.setStatus(HttpServletResponse.SC_OK);
                context.inputMapper.writerWithType(WorkerHolder.WORKER_SYNC_RESP_TYPE_REF)
                                   .writeValue(asyncContext.getResponse().getOutputStream(), result);
                asyncContext.complete();
              }
              catch (Exception ex) {
                log.debug(ex, "Request timed out or closed already.");
              }
            }
  
            @Override
            public void onFailure(Throwable th)
            {
              try {
                HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse();
                if (th instanceof IllegalArgumentException) {
                  response.sendError(HttpServletResponse.SC_BAD_REQUEST, th.getMessage());
                } else {
                  response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, th.getMessage());
                }
                asyncContext.complete();
              }
              catch (Exception ex) {
                log.debug(ex, "Request timed out or closed already.");
              }
            }
          }
      );
  
      asyncContext.setTimeout(timeout);
    }