Протокол Beanstalk

Материал из support.qbpro.ru

Это перевод официального протокола Beanstalk Резервная копия

переводчик Андрей Климов.

08-05-2014

Протокол

Протокол beanstalk работает поверх TCP используя кодировку ASCII. Клиенты могут устанавливать соединение, посылать команды и данные, а так же закрывать соединение. Для каждого соединения, сервер обрабатывает команды последовательно в порядке, в котором они были получены и посылает ответы в том же порядке. Все целые числа в протоколе отформатированы в десятичной форме и (если не указано иное) неотрицательны.

Названия в протоколе — строки в кодировке ASCII. Они могут содержать буквы (A-Z и a-z), цифры (0-9), знаки "-", "+", "/", ";", ".", "$", "_" и скобки "(" и ")", но не могут начинаться со знака "-". Названия разделяются символом пробел или символом конец строки. Каждое название должно быть длинной не менее одного символа.

Протокол содержит два вида данных: текстовые строки и неструктурированные куски данных. Текстовые строки используются для клиентских команд и ответов сервера. Части данных используются для передачи «тела» задачи и статистики. Каждое «тело» задачи является неразделенной последовательностью байтов. Сервер никогда не проверяет или изменяет «тело» задачи и всегда отправляет его обратно в его первоначальном виде. Это зависит только от клиентов, чтобы договориться о содержательной интерпретации «тел» задач.

Клиент может использовать команду «quit» или просто закрыть TCP соединение когда он больше не будет использовать сервер. Тем не менее, beanstalkd очень хорошо работает с большим количеством открытых соединений, поэтому обычно лучше для клиента, чтобы тот сохранил своё соединение открытым и использовал его как можно дольше. Это позволяет избежать расходов, связанных на установление новых сессий TCP.

Если клиент нарушает протокол (например, отправив не очень хорошо сформированный запрос или несуществующую команду) или в сервере произошла ошибка, сервер ответит одним из следующих сообщений об ошибке:

  • OUT_OF_MEMORY\r\n - Сервер не может выделить память для задачи. Клиенту нужно попробовать еще раз позже.
  • INTERNAL_ERROR\r\n - Эта ошибка сигнализирует о критической ошибке сервера. Такого не должно случиться никогда. Если такое произойдет, пожалуйста сообщите по адресу http://groups.google.com/group/beanstalk-talk.
  • BAD_FORMAT\r\n - Клиент послал неверно сформированную команду. Это может случится в случаях, если команда не заканчивается символом \r\n, если в позиции где ожидаются целое число, а находится иное, если неправильное количество аргументов или если командная строка неправильно формируется любым другим способом.
  • UNKNOWN_COMMAND\r\n - Клиент послал неизвестную для сервера команду

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

В крайнем случае, если в сервере случилась критическая ошибка, которая приводит к прекращению обслуживания текущего клиента, сервер закроет соединение. (Прим переводчика. Далее по тексту клиенты, которые создают (генерируют) задачу будут называться генераторами задач, клиенты которые исполняют задачу, исполнителями задач).

Жизненный цикл задачи

Задачи в beanstalk создаются клиентами командой «put». На протяжении своей «жизни», задача может находится в одном из четырех состояний: «ready», «reserved», «delayed», или «buried». После создания командой «put», задача обычно переходит в состояние ready. Она ожидает в очереди ready до тех пор, пока не подключиться исполнитель и не даст команду «reserve» (прим переводчика: исполнитель может быть уже подключенным и просто дать команду «reserve» — зарезервировать за собой следующую в очереди задачу, находящуюся в состояние ready, как выполняемую. Можно перефразировать - зарезервировать следующую задачу в очереди ready. Состояние и очередь в данном случае одно и тоже). Если есть такая задача следующая в очереди, то она будет зарезервирована за исполнителем. Исполнитель выполняет задачу, после чего исполнитель посылает команду «delete», для её удаления.


На схеме типовой жизненный цикл задачи:

   put            reserve               delete
  -----> [READY] ---------> [RESERVED] --------> *poof*

На этой схеме приведены все возможные варианты:

   put with delay               release with delay
  ----------------> [DELAYED] <------------.
                        |                   |
                        | (time passes)     |
                        |                   |
   put                  v     reserve       |       delete
  -----------------> [READY] ---------> [RESERVED] --------> *poof*
                       ^  ^                |  |
                       |   \  release      |  |
                       |    `-------------'   |
                       |                      |
                       | kick                 |
                       |                      |
                       |       bury           |
                    [BURIED] <---------------'
                       |
                       |  delete
                        `--------> *poof*


Система имеет один или более каналов. Каждый канал состоит из очередей ready и delay. Каждое задание проводит всю свою «жизнь» в одном канале. Клиенты могут подписаться на канал, отправив команду «watch»; они могут отписаться от канала, отправив команду «ignore». Этот набор каналов, на которых осуществлена подписка, является как говорят, «watch list» клиента. Когда клиент посылает команду «reserve», задача может поступить из любого канала в «watch list».


Когда клиент подключается, его «watch list» он изначально подписан только на канал «default». Если он посылает команду «reserve» без предварительного использования команды «use», то все его задачи будут находится только в канале «default».


Каналы создаются по запросу, всякий раз когда на них ссылаются. Если канал пуст (это означает, что он не содержит задач со статусом «ready», «delayed» или «buried») и нет подписанных клиентов, канал будет удален.

Команды генерации.

Команда «put» предназначена для любого клиента, который желает добавить задачу в очередь. Она включает в себя строку команды с последующей строкой «тела» задачи:

put <pri> <delay> <ttr> <bytes>\r\n

<dаta>\r\n

Добавляет задачу в используемый клиентом в настоящее время канал (см. ниже команду «use»).

  • <pri> приоритет - целое число < 2**32. Задачи с меньшим значением приоритета будут выполнены раньше задач с большим значение приоритета. Самая важная задача будет иметь приоритет 0; самая неважная задача будет иметь приоритет 4,294,967,295.
  • <delay> отсрочка — целое число секунд ожидания до постановки задачи в очередь «ready». Все это время задача будет иметь статус «delayed».
  • <ttr> время выполнения — целое число секунд, которые отводятся исполнителю на выполнение этой задачи. Это время отсчитывается с момента начала выполнения команды «reserve» для этой задачи. Если исполнитель не даст команду «delete», «release» или «bury» для этой задачи через <ttr> секунд, будет превышено время выполнения и сервер выполнит команду «release» для этой задачи. Минимальное значение 1. Если клиент устанавливает значение <ttr> равным 0, сервер без предупреждения увеличит его до 1.
  • <bytes> размер тела задачи — целое число указывающее размер тела задачи, не включая граничные символы "\r\n". Это значение должно быть меньше чем max-job-size (по умолчанию: 2**16).
  • <dаta> тело задачи — последовательность байтов длиной <bytes> указанной в строке команды.

После отправки строки команды и тела задачи, клиент должен ожидать один из возможных ответов:

  • INSERTED <id>\r\n - указывает на успешное добавление задачи.
    • <id> - целое число, идентификатор новой задачи
  • BURIED <id>\r\n - указывает на то, что серверу не хватило памяти при попытке разобрать структуру данных очереди приоритетов.
    • <id> - целое число, идентификатор новой задачи
  • EXPECTED_CRLF\r\n - тело задачи должно оканчиваться парой символов CR-LF, а именно, "\r\n". Эти два байта не учитываются в при расчете длины тела задачи в строке команды put.
  • JOB_TOO_BIG\r\n - клиент передает тело задачи больше чем max-job-size байт
  • DRAINING\r\n - означает, что сервер находится в режиме "drain mode" и больше не принимает новые задачи. Клиент должен попробовать подключиться к другому серверу или повторить подключение позже.

Команда «use» предназначена только для генераторов команд. Последующие команды «put» добавят задачу в канал, предусмотренный настоящей командой. Если не был дана команда «use», задачи будут добавлены в канал под названием «default».

use <tube>\r\n

  • <tube> - название канала, длиной не более 200 байт. Указывает какой канал станет текущим для использования. Если такого канала нет, то он будет создан.

Возможен только один вариант ответа:

  • USING <tube>\r\n - указывает имя используемого канала
    • <tube> - Имя канала, который стал текущим


Команды исполнителей

Клиент, который хочет получить задачу из очереди должен использовать команды «reserve», «delete», «release» и «bury» (прим переводчика: если точнее, то это набор команд исполнителя для работы с очередью в канале).

reserve, reserve-with-timeout

Первая команда исполнителя «reserve», выглядит так:

reserve\r\n

Альтернативно можно указать тайм-аут следующим образом:

reserve-with-timeout <seconds>\r\n

Команды вернут вновь зарезервированную задачу. Если не будет доступных для резервирования задач, beanstalkd будет ожидать возможности послать ответ, до тех пор пока это не станет возможным. После того, как задача будет зарезервирована за для клиента, у клиента есть строго ограниченное время (TTR) для выполнения задачи. При наступлении тайм-аута задачи, сервер будет поставить работу обратно в очередь готовности. И TTR и фактическое время выполнения можно найти в статистике по команде stats-job.

Если более одной задачи имеют статус ready, beanstalkd выберет одну из них с наименьшим значением приоритета. В рамках одного приоритета, будет выбрана та задача, которая была получена первой.

Тайм-аут со значением 0 заставит сервер немедленно возвращать либо ответ или TIMED_OUT . Положительное значение тайм-аута будет задавать время, в течении которого запросы «reserve» будет блокированы пока задача снова не станет доступной.

Всё время TTR зарезервированной задачи, вплоть до последней секунды сервер будет находится в безопасном режиме, при котором исполнитель гарантированно не может получить другую задачу. Если исполнитель дает команду «reserve» во время безопасного режима или безопасный режим наступает пока исполнитель ожидает ответ на команду «reserve», сервер может ответить следующим образом:

  • DEADLINE_SOON\r\n - дает исполнителю шанс дать команду «delete» или «release» для зарезервированной задачи, до того как сервер автоматически даст команду «release» для зарезервированной задачи.
  • TIMED_OUT\r\n - если был указан неотрицательный тайм-аут и тайм-аут превышен до момента, когда задача стала доступна, или если соединение клиента является полузакрытыми, сервер ответит TIMED_OUT

В противном случае, единственным ответом на эту команду является успешное резервирование задачи в виде текстовой строки, затем тела задачи:

  • RESERVED <id><bytes>\r\n - успешное резервирование задачи
    • <id> - имя канала, который стал текущим
    • <bytes> - целое число указывающее размер тела задачи, не включая граничные символы "\r\n".
  • <dаta>\r\n - тело успешно зарезервированной задачи — последовательность байтов длиной <bytes> указанной в строке команды. Это точная копия байтов, которые были изначально отправлены на сервер командой «put» в этой задаче.

delete

Команда «delete» удаляет задачу с сервера целиком. Эта команда, как правило, используется клиентом, когда задача успешно выполнена. Исполнитель может удалять задания, которые он зарезервировал, а так же задачи со статусом «ready», «delayed» или «buried». Команда «delete» выглядит следующим образом:

delete <id>\r\n

  • <id> - идентификатор задачи, которую следует удалить.

Исполнитель должен ожидать один из возможных вариантов ответа:

  • DELETED\r\n - сигнализирует об успешности операции
  • NOT_FOUND\r\n - если задача не существует, или была зарезервирована не этим исполнителем, была переведена в статус ready или buried (прим переводчика: неоднозначный, возможно неправильный перевод). Эта ситуация возможна в случае, когда тайм-аут для задачи наступил раньше, чем клиент дал команду «delete»

release

Команда «release» помещает зарезервированную задачу назад в очередь ready (и помечает её статус как «ready») для запуска любым исполнителем. Обычно это используется, когда выполнить задачу не удается из-за возникшей ошибки.

Формат команды:

release <id> <pri> <delay>\r\n

  • <id> идентификатор задачи, которую следует «реализовать».
  • <pri> новый приоритет для задачи.
  • <delay> целое число секунд ожилания, до того как задача переместится в очередь ready. В течение этой задержки задача будет иметь статус «delayed».

Исполнитель должен ожидать один из возможных вариантов ответа:

  • RELEASED\r\n - сигнализирует об успешности операции
  • BURIED\r\n - указывает на то, что серверу не хватило памяти при попытке разобрать структуру данных очереди приоритетов.
  • NOT_FOUND\r\n - если задача не существует или была зарезервирована не этим исполнителем

bury

Команда «bury» переводит задачу в статус «buried». Такие задачи помещаются в FIFO подобный список и не обрабатываются сервером до тех пор, пока исполнитель не даст команду «kick».

Формат команды:

bury <id> <pri>\r\n

  • <id> идентификатор задачи, которую следует «заморозить» (прим переводчика: в оригинальном тексте про команду release).
  • <pri> новый приоритет, назначенный задаче.

Возможны два варианта ответа:

  • BURIED\r\n - сигнализирует об успешности операции
  • NOT_FOUND\r\n - если задача не существует или была зарезервирована не этим исполнителем

touch

Команда "touch" позволяет исполнителю запросить больше времени на выполнение задачи. Это полезно для задач, которые потенциально выполняются долго, но вы продолжаете использовать преимущества TTR при выполнении затянувшейся задачи не зависшим исполнителем. Исполнитель может ппереодически говорить серверу что он по-прежнему жив и выполняет задачу (например исполнитель может так делать при поступлении команды DEADLINE_SOON). Команда откладывает автоматическое выполнение команды «release» зарезервированной задачи на TTR секунд с момента поступления команды.

Формат команды:

touch <id>\r\n


  • <id> идентификатор задачи, зарезервированной в текущем соединении.

Возможны два варианта ответа:

  • TOUCHED\r\n - сигнализирует об успешности операции
  • NOT_FOUND\r\n - если задача не существует или была зарезервирована не этим исполнителем

watch

Команда «watch» добавляет именованный канал в watch list текущего соединения. Команда «reserve» принимает задачи из любого канала в watch list. Для каждого нового соединения создаётся новый watch list, содержащий только один канал, называемый «default».

Формат команды:

watch <tube>\r\n

  • <tube> название канала, длиной не более 200 байт. Указывает какой канал будет добавлен в watch list. Если такого канала нет, то он будет создан.

Возможный ответ:

WATCHING <count>\r\n

  • <count> целое число каналов в текущем watch list.

ignore

Команда «ignore» только для исполнителей. Она удаляет именованый канал из watch list для текущего соединения.

Формат команды:

ignore <tube>\r\n

Возможен один из вариантов ответа:

  • WATCHING <count>\r\n сигнализирует об успешности операции
    • <count> целое число каналов в текущем watch list.
  • NOT_IGNORED\r\n" если клиент пытается игнорировать единственный канал в его watch list.