Play Framework: Влияние рабочих мест на модель без гражданства

Одна из замечательных особенностей платформы Play заключается в том, что она полностью без гражданства и ориентирована только на запросы/ответы. Это действительно приятно, поскольку он позволяет мне развернуть мое приложение в облаке и масштабировать количество экземпляров воспроизведения за моим балансиром нагрузки, не беспокоясь о репликации состояния (сеанса)...

Тем не менее, в последнее время мне нужно было выполнить некоторую логику приложения за пределами HTTP-запроса и выяснили, что Play имеет возможность определять задания, которые полностью управляются инфраструктурой. Звучит блестяще, но возникает вопрос: как эти задания вписываются в модель без состояния, используемую Play?

Скажем, у меня есть задача обслуживания, которая должна запускаться каждый час, и я определяю запланированную работу для этого. Если я затем разворачиваю несколько экземпляров Play за балансировщиком нагрузки, будет ли это задание запускаться одновременно в каждом экземпляре? И если да, то какой был бы хороший подход для обработки заданий, которые должны выполняться "исключительно"?

Я думал создать новый экземпляр воспроизведения на некластерном сервере, повторно используя модель JPA существующего (кластерного) экземпляра (и, таким образом, подключиться к той же базе данных). Этот новый экземпляр будет содержать только задания на обслуживание, и поскольку он размещен на некластеризованном сервере, нет риска одновременной работы задания. В то же время, это позволило бы мне сохранить мой существующий, сгруппированный экземпляр полностью без гражданства и легко разместить/загрузить баланс. Будет ли это хорошим подходом?

Ответ 1

Я бы рекомендовал также сгруппировать задание. Вы можете установить семафор в базе данных, чтобы гарантировать, что выполняется только одно задание. Другая идея - взглянуть на Akka-Framework, который будет включен в Play 2.0. Я думаю, что он создал механизм с этой проблемой, но я не уверен. У меня нет опыта с аккой.

Ответ 2

Как упоминалось выше, сохранение флага в БД помогает выяснить, работает ли работа. Я использую семафор db с другими флагами, чтобы дать мне статус задания и дополнительную информацию.

Еще одна вещь, которую вы можете сделать, - это использовать Play.id для разработки и определения того, какой экземпляр должен выполнять задания. Мы используем "play start -% prod", "play start -% prod1"... для запуска приложений и следующего в моем методе doJob():


doJob(){
   if ("prod".equalsIgnoreCase(Play.id)) {
   ...
   }
}

Ответ 3

Если бы вы быстро взглянули на исходный код Play Framework (классы Job и JobsPlugin), я думаю, что они не подходят для использования в среде кластера, когда важно, чтобы Job выполнялось только один раз за какое-то время интервал (без введения уродливых хаков).

Я вижу три возможных решения:

  • Используйте планировщик заданий, который поддерживает кластеризацию. Очевидным выбором является Quartz. Play также использует части Quartz (для анализа выражений CRON), но не для той части, которая выполняет планирование.

  • При использовании Play 2, возможно, для Akka, который предлагает планировщик.

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