Как избежать повторения запроса в параллельном режиме - PullRequest
0 голосов
/ 05 декабря 2018

Для данного запроса, такого как /api/user/1, предположим, что для запроса из db потребуется 10 с.

Итак, сначала сервер принимает один запрос, и служба начинает запрашивать базу данных.Затем, во время запроса, может быть еще несколько входящих запросов (все для /api/user/1).

Как избежать последующих запросов к базе данных?Мы не имеем в виду кеш, мы просто хотим, чтобы точно такой же запрос не происходил в одно и то же время .

Имеет ли это какой-то смысл?Если да, как это сделать (Возьмите в качестве примера приложение Java или приложение узла) *

1 Ответ

0 голосов
/ 05 декабря 2018

Вы можете использовать ConcurrentHashMap (см. здесь ), который отображает строки маршрута, такие как "/api/user/1", в List обратных вызовов, принимающих один параметр типа T (замените T накакой класс вы используете для хранения результатов запроса).Ваш метод request должен будет использовать Consumer<T> для обратного вызова.Если вы не знакомы с Consumer<T>, вы можете прочитать об этом здесь .Это просто интерфейс, представляющий функцию, которая принимает один параметр типа T и ничего не возвращает.

Когда поток хочет получить результат запроса к маршруту, он должен вызвать синхронизированный метод register, которыйпринимает маршрут как String и обратный вызов и выполняет следующее:

Следует проверить, является ли маршрут ключом в Map.Если это не так, он должен добавить маршрут в качестве ключа к Map со значением, равным List, содержащим одно значение, обратный вызов, предоставленный в параметре, и затем он должен инициировать запрос с обратным вызовом кметод resolve, о котором я расскажу ниже.Если маршрут уже был ключом в Map, то обратный вызов потока должен быть просто добавлен к List в Map, где маршрут является ключом.

Функция resolveдолжен принять маршрут как String и результат запроса типа T.Затем он должен получить List в ключе маршрута, удалить ключ маршрута из Map, и, наконец, перебрать все обратные вызовы и вызвать их с результатом запроса.

Я написал некоторый кодс примером, но я не проверял его.

CallbackHandler.java

public abstract class CallbackHandler<T> {
    private QueryRepetitionHandler<T> handler;
    private CountDownLatch latch;
    private T result;

    public CallbackHandler(QueryRepetitionHandler<T> handler) {
        this.handler = handler;
        latch = new CountDownLatch(1);
    }

    public void resolve(T result) {
        this.result = result;
        latch.countDown();
    }

    public void request(String route) {
        handler.register(route);
        latch.await();
    }
}

QueryRepetitionHandler.java

public abstract class QueryRepetitionHandler<T> {
    private Map<String, List<CallbackHandler<T>> map = new ConcurrentHashMap<>();

    protected abstract void request(String route, Consumer<T> consumer);

    public synchronized void register(String route, CallbackHandler<T> handler) {
        if (map.containsKey(route)) {
            map.get(route).add(callback);
        } else {
            List<CallbackHandler<T>> list = new ArrayList<>();
            list.add(callback);
            map.put(route, list);
            request(route, result -> resolve(route, result));
        }
    }

    private void resolve(String route, T result) {
        List<Consumer<T>> list = map.remove(route);

        // Sanity check
        if (list != null) {
            list.forEach(handler -> handler.resolve(result));
        }
    }
}

Вы хотите создать один экземпляр QueryRepetitionHandler<T> чтобы быть доступным для всех ваших тем.Когда поток хочет сделать запрос, он должен создать экземпляр CallbackHandler<T>, используя общий QueryRepetitionHandler<T>.Конечно, вы не можете создать экземпляр QueryRepetitionHandler<T> без реализации метода request.Метод request должен просто сделать запрос и затем вызвать обратный вызов, предоставленный как Consumer<T>.Затем следует вызвать request метод CallbackHandler<T> с желаемым маршрутом в качестве аргумента String.Затем этот поток будет ожидать (используя latch.await()) результата запроса, пока QueryRepetitionHandler<T> не вызовет свой метод resolve с результатом и не вызовет latch.countDown().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...