2009-04-24 4 views
1

Я разрабатываю приложение, которое запрашивает веб-сервис Musicbrainz. Я прочитал в руководстве musicbrainz не более одного запроса в секунду для веб-службы или IP-адрес клиента будет заблокирован.Служба с ограниченным сроком службы

Какую архитектуру вы предлагаете, чтобы сделать это ограничение прозрачным для клиента службы.

  • Я хотел бы назвать метод (например, getAlbuns), и он должен сделать запрос 1сек после последнего запроса.
  • Я также хочу вызвать сразу 10 запросов, и служба должна обрабатывать очередность, возвращая результаты при доступности (без блокировки).

Спасибо!

+0

я предполагаю, вы создаете приложение на рабочем столе? –

+0

Да, это правильно! –

ответ

1

из-за требуемой задержки между двумя запусками, я бы предложил java.util.Timer или java.util.concurrent.ScheduledThreadPoolExecutor. Timer очень просто и идеально подходит для использование кейс. Но если дополнительные требования к планированию идентифицируются позже, один из Executor может обрабатывать все из них. В любом случае используйте метод с фиксированной задержкой, а не метод с фиксированной ставкой.

Повторяющаяся задача polls параллельная очередь для объекта запроса. Если есть ожидающий запрос, задача выполняет его и возвращает результат через обратный вызов. Запрос для службы и обратный вызов для вызова являются членами объекта запроса.

Приложение сохраняет ссылку на общую очередь. Чтобы запланировать запрос, просто добавьте его в очередь.


Чтобы уточнить, если очередь выполнена при выполнении запланированной задачи, запрос не выполняется. Простой подход состоял бы только в том, чтобы закончить задачу, и планировщик вызовет задачу через секунду, чтобы снова проверить.

Однако это означает, что для запуска задачи может потребоваться до одной секунды, даже если в последнее время запросы не обрабатывались. Если эта ненужная задержка является невыносимой, писать собственный поток, вероятно, предпочтительнее использовать Timer или ScheduledThreadPoolExecutor. В вашем собственном цикле синхронизации у вас больше контроля над планированием, если вы решили блокировать пустую очередь до тех пор, пока запрос не будет доступен. Встроенные таймеры не гарантированно ждут полной секунды после предыдущего выполнения завершено; они обычно планируют относительно начало времени задачи.

Если этот второй случай - это то, что вы имеете в виду, ваш метод run() будет содержать цикл. Каждая итерация начинается с blocking в очереди до получения запроса, а затем записывает время. После обработки запроса время снова проверяется. Если разница во времени меньше одной секунды, sleep для остатка. Эта установка предполагает, что требуется одна секунда задержки между началом одного запроса и следующей. Если требуется задержка между окончанием одного запроса и следующей, вам не нужно проверять время; просто спать в течение одной секунды.

Еще одна вещь, которую следует учитывать, заключается в том, что служба может принимать несколько запросов в одном запросе, что уменьшит накладные расходы. Если это так, воспользуйтесь этим, заблокировав take() для первого элемента, затем используя poll(), возможно, с очень коротким временем блокировки (5 мс или около того), чтобы узнать, делает ли приложение больше запросов. Если это так, они могут быть объединены в один запрос к службе. Если queue является BlockingQueue<? extends Request>, это может выглядеть примерно так:

Collection<Request> bundle = new ArrayList<Request>(); 
    bundle.add(queue.take()); 
    while (bundle.size() < BUNDLE_MAX) { 
     Request req = queue.poll(EXTRA, TimeUnit.MILLISECONDS); 
     if (req == null) 
     break; 
     bundle.add(req); 
    } 
    /* Now make one service request with contents of "bundle". */ 
+0

Но я не хочу делать запрос каждую секунду. Я хочу убедиться, что когда клиент сделает запрос, он выполнит только 1сек после последнего. –

+0

Справа, Марцио. Я не хотел этого подразумевать; Я уточню свой ответ, чтобы уточнить. – erickson

1

Вам необходимо определить локальную «прокси-службу», которую вызовут ваши местные клиенты.

Местный прокси получит запросы и передаст их реальному сервису. Но только со скоростью одного сообщения в секунду.

Как вы это сделаете, это в значительной степени зависит от доступной вам технологии.

Простейшим будет mutithreaded Java службы с статическим и синхронизируется LastRequestTime долго;.»Переменная метка времени (хотя вам потребуется несколько кодов акробатики, чтобы сохранить ваши запросы в последовательности)

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

Смежные вопросы