# Workers

MDN (opens new window) определяет Web Worker-ы так:

Web Worker-ы предоставляют простое средство для запуска скриптов в фоновом потоке. Поток Worker'а может выполнять задачи без вмешательства в пользовательский интерфейс.

ES4X не является браузером, и не заботится о пользовательском интерфейсе, но вы можете запускать долго бегущие задачи на стороне сервера. Все вызовы в Vert.x - неблокирующие, потому даже создание Web Worker должно следовать этой семантике. По этой причине мы не может строго следовать интерфейсу Worker и используем фабричный метод вместо конструктора.

Предположим, что вам необходимо запустить процессороёмкую задачу. Так как вы не должны блокировать событийный цикл, логичным шагом является использование Worker Verticle. Worker API соотносится с Vert.x API с некоторыми нюансами.

# Пример Worker

Представим следующий код Worker:

// Получаем ссылку на класс Thread с целью блокировки...
const Thread = Java.type('java.lang.Thread');

// Контекст Worker доступен через переменную `self` как в документации MDN
self.onmessage = function(e) {
  console.log('Получено сообщение от главного скрипта, спим 5 секунд...');
  // Внесем немного хаоса в событийный цикл
  Thread.sleep(5 * 1000);
  var workerResult = 'Результат: ' + (e.data[0] * e.data[1]);
  console.log('Отправляем сообщение в главный скрипт');
  // возвращаем данные в главный Verticle
  postMessage(workerResult);
};

# Что нужно знать

Worker-ы загружаются в отдельных контекстах, так что вы не можете совместно использовать функции главного verticle и worker, все взаимодействие происходит через отправку сообщений (eventbus) с помощью:

  • postMessage() отправляет сообщение
  • onmessage принимает сообщение

# Со стороны Verticle

Часть API, отвечающая за Verticle, позволяет вам получать ошибки и завершать worker-ы c помощью terminate(), в отличие от самого worker.

# Пример Verticle

Worker.create('workers/worker.js', function (create) {
  if (create.succeeded()) {
    var worker = create.result();

    worker.onmessage = function (msg) {
      console.log('onmessage: ' + msg);
    };

    worker.onerror = function (err) {
      console.err(err);
      // завершаем worker
      worker.terminate();
    };

    console.log('отправляем...');
    worker.postMessage({data: [2, 3]});
  }
});

Теперь код Thread.sleep(5000), который нельзя было запускать из событийного цикла, работает в worker-потоке, тем самым оставляя поток событийного цикла доступным для всех других задач на чтение/запись.

# Worker-ы на других языках

Есть возможность создавать не JavaScript worker-ы. Worker-ы должны следовать следующему небольшому списку правил:

  • Worker должен зарегистрировать адрес: {deploymentId}.out для получения сообщений от главного скрипта.
  • Worker должен отправлять сообщения для главного скрипта на адрес: {deploymentId}.in.
  • Содержимое сообщений должно использовать JSON.stringify(message) во избежание проблем между языками.
  • Ожидается, что Worker-ы будут локальными, если вы хотите подключиться к worker откуда угодно в кластере, используйте конструктор с дополнительным аргументом true, например: new Worker('deploymentId', true).