Статьи

Представляем ElasticMQ: альтернатива Scala SQS

Желая изучить Scala и некоторые новые библиотеки Scala / Java, я начал писать ElasticMQ . Это простая система организации очередей сообщений, которая тщательно следует семантике Amazon SQS и предоставляет интерфейс, подобный REST SQS. В настоящее время выполняются только основные операции. ElasticMQ может быть полезен в качестве замены SQS, например, для тестирования приложений SQS.

Моя цель состояла в том, чтобы сделать использование максимально простым, поэтому для создания нового узла и предоставления интерфейса REST все, что вам нужно сделать, это:

val node = NodeBuilder.createNode
val server = SQSRestServerFactory.start(node.nativeClient, 8888,
                 "http://localhost:8888")

Теперь просто укажите вашему клиенту SQS http: // localhost: 8888, и вы сможете создавать / удалять очереди, изменять время ожидания видимости, отправлять и получать сообщения.
Когда вы закончите использовать ElasticMQ, вы можете выключить узел и сервер:

server.stop()
node.shutdown()

Весь исходный код доступен на GitHub . Смотрите readme для получения инструкций о том, как добавить ElasticMQ в качестве зависимости к вашему Maven или SBT-проекту.

С технической стороны ElasticMQ использует ряд интересных вещей.

Во-первых, есть Netty , асинхронная управляемая событиями Java-инфраструктура Java. Я использовал Netty для реализации REST-сервера. Все запросы обрабатываются неблокирующим образом.

В настоящее время сообщения хранятся в базе данных H2 в памяти (но это можно легко изменить, указав, например, на базу данных MySQL или PostgreSQL), и управляются с помощью
библиотеки Squeryl Scala. Squeryl позволяет писать SQL-запросы в виде типичного безопасного кода Scala, например

update(messages)(m =>
  where(m.id === message.id and m.lastDelivered === message.lastDelivered)
    set(m.lastDelivered := lastDelivered))

Для тестирования интеграции я использую библиотеку Typica .

На стороне Scala я создал простой внутренний DSL для определения обработчиков отдыха. Сервер (который использует Netty) является универсальным и может быть снабжен любым количеством «обработчиков отдыха», на которые отправляются запросы. Каждый обработчик отдыха указывает, на какой путь он будет реагировать, какие параметры требуются и что следует запускать в ответ на запрос. Например:

val handler1 = (createHandler
   forMethod GET
   forPath (root / "products" / %("name") / "price")
   requiringParameters List("currency", "quantity")
   requiringParameterValues Map("department"->"electronics")
   running electronicsPriceRequestLogic)
 
val server = RestServer.start(handler1 :: handler2 :: … :: Nil, 8888)

См. Файл RequestHandlerLogic для реализации и RequestHandlerBuilderTestSuite для примера использования.

На самом деле есть еще один маленький DSL для определения путей. Например (root / «a» / «b» / «c») будет соответствовать только a / b / c, но (root / «a» /% («p1») / «c») будет соответствовать a / что угодно / c, со средним компонентом, назначенным параметру p1. Вы также можете использовать регулярные выражения, например (root / «a» / «» «[a-z0-9] +» «». R / «c») для сопоставления компонентов пути. См. Класс RestPath и тест для деталей.

Не уверен, куда ElasticMQ пойдет в будущем, но я могу представить множество интересных возможностей. Так что следите за обновлениями :).

Комментарии о коде, стиле Scala, использовании Netty / Squeryl приветствуются! Как и любые другие идеи, предложения по улучшению и т. Д.

Адам