EventMachine

Gem позволяет быстро и достаточно просто организовать многопоточную обрабтку ввода-вывода. Имеет свой внутренний пул подключений.

Установка

Достаточно принести сам gem:

gem install eventmachine

Использование

В своём проекте я применял его в двух ипостасях - для отслеживания изменений в директориях и для работы с tcp сокетом.

Простейший tcp сервер

Принцип следующий - создаётся класс-потомок EventMachine::Connection, в котором переопределяются нужные методы. Выбор достаточно большой, я использовал два

  • post_init - выполняется сразу после инициализации объекта, пере получением каких-либо данных от пользователя
  • recieve_data(data) - метод, в который передаются полученные от клиентской стороны данные, все обработки происходят здесь

А вот и пример кода

require 'json'
require 'eventmachine'
 
module OwlStore
  class Server < EventMachine::Connection
    def post_init
      puts "Recieved a new connection"
    end
 
    def receive_data(data)
      data.chomp!
      puts "Recieved data is '#{data}'"
      begin
        data = JSON.parse(data)
        send_data(JSON.generate({statue:'ok'}))
      rescue => e
        send_data(JSON.generate({error:"Malformed JSON data: #{e}"}))
      end
      close_connection_after_writing
    end
  end
end
 
EventMachine.run {
  EventMachine.start_server '127.0.0.1', 8800, OwlStore::Server
}

INotify

Иногда возникает желание отслеживать что происходит в директории или непосредственно с файлами, чтобы соответствующим образом обрабатывать события. Можно конечно держать свой собственный цикл, который будет постоянно дёргать содеримое файла/директории, а можно завязаться на замечательную способность ОС Linux - inotify. Всю обвязку уже сделали за нас, нам остаётся только сесть и поехать.

Как и с tcp сервером мы создаём класс потомок, только на этот раз унаследованный от EventMachine::FileWatch. Кстати во все классы потомки можно передавать свои собственные аргументы, что может упростить впослежствии разработку. (Например можно отказаться от глобальной переменной конфигурации и передавать в объект только нужные части) В своём классе потомке я переопределил опять же два метода, но на этот раз это стал конструктор и

  • file_modified - вызывается в момент, когда изменяется файл/директория

Попутно доступны

  • file_moved - вызывается, когда файл/директория перемещены
  • file_deleted - вызывается при удалении файла/директории
  • unbind - вызывается при завершении работы объекта

И сразу же пример1)

require "eventmachine"
 
module OwlServer
  class Queue < EventMachine::FileWatch
    def initialize(config)
      puts "INotify watcher configured with #{config}"
      @config = config
    end
 
    def file_modified
      puts "#{path} modified"
    end
 
    def file_moved
      puts "#{path} moved"
    end
 
    def file_deleted
      puts "#{path} deleted"
    end
 
    def unbind
      puts "#{path} monitoring ceased"
    end
  end
end
 
Dir.mkdir("/tmp/uploads/") unless Dir.exists? ("/tmp/uploads/")
 
EventMachine.run {
  EventMachine.watch_file("/tmp/uploads/", OwlServer::Queue, {config: 'true'})
}
1)
я совсем чуть чуть поленился и взял пример с сайта производителя, но всё равно поправил