Правильный способ поддерживать много связей с целлулоидом?
В настоящее время я работаю над приложением, которое извлекает почту из многих почтовых ящиков IMAP. Похоже, что Целлулоид не подходит для этой роли, но я не уверен, как нанять актеров.
Приложение будет работать в распределенном режиме. Есть x почтовых ящиков для опроса и y процессов, среди которых они будут разделены. Таким образом, у каждого процесса есть список почтовых ящиков, которые они должны опрашивать, и этот список будет меняться время от времени. Это означает, что пул соединений, поддерживаемых каждым процессом, является динамическим.
Мой самый большой вопрос: должен ли я создавать отдельный актер ImapConnection для каждого почтового ящика или я должен создать один актер ImapListener, который управляет всеми соединениями внутри?
Мой нынешний дизайн показывает прежнее решение. Есть один центральный субъект-координатор, который хранит множество действующих лиц, каждый из которых управляет одним подключением к imap. Новое соединение добавляется с помощью простого:
@connections << ImapConnection.supervise(account_info)
ImapConnection либо опрашивает сервер IMAP через регулярные промежутки времени, либо поддерживает соединение IDLE. Если Координатор хочет прекратить опрос почтового ящика, он ищет его в своем массиве @connections и правильно удаляет его.
Для меня это кажется логичным подходом, который дает много преимуществ Celluloid (например, автоматический перезапуск разбившихся актеров), но я изо всех сил пытаюсь найти примеры другого программного обеспечения, которое использует этот подход. Правильно ли используется модель актера для сотен актеров, или я должен использовать другой подход?
1 ответ
Очень рад слышать, что вы используете Celluloid
, Хороший вопрос.
Не уверен, как вы создаете соединения и поддерживаете их, будь то TCPSocket
у вас есть возможность управлять или нет. Если у вас есть возможность управлять TCPSocket
напрямую, вы должны использовать Celluloid::IO
так же как Celluloid
сам. Я также не знаю, куда вы помещаете информацию, извлеченную из подключений IMAP. Эти две вещи влияют на вашу стратегию.
Ваш подход не плохой, но да - его можно улучшить, добавив что-то, чтобы сделать вашу тяжелую работу, опросить рабочих; другой держать account_info
только; и последний актер, чтобы запустить работу и / или поддерживать состояние IDLE. Так что вы бы в конечном итоге ImapWorker
(бассейн), ImapMaintainer
, а также ImapRegistry
, Прямо здесь, мне интересно, если вы проводите опрос, нужно ли вам сохранять открытое соединение, а не разрешать передачу информации. Если вы планируете опросить и по-прежнему сохранять открытые связи, вот что сделали бы эти три субъекта:
ImapRegistry
держит ваш account_info
в Hash
, Это будет иметь методы, такие как add
, get
, а также remove
, Я рекомендую Hash
из @credentials
так что вы можете использовать один и тот же идентификатор между ImapMaintainer
а также ImapRegistry
; каждый держит живые связи в своем @connections
и один держит account_info
случаи в его @credentials
, И то и другое @connections
а также @credentials
доступны по одному и тому же идентификатору, но один поддерживает энергозависимое соединение, тогда как другой имеет только статические данные, которые можно использовать для воссоздания соединения в случае необходимости. Таким образом, ваши тяжелые атлеты могут умереть, возродиться, и вся система сможет восстановиться.
ImapMaintainer
будет иметь фактическое @connections
в этом и every( interval ) { }
задачи, встроенные в него, добавляются к account_info
хранится в ImapRegistry
, Я вижу две задачи, в зависимости от того, с какой частотой вы планируете опросить. Одним из них может быть простое прикосновение к соединению IMAP для его поддержания, а другим - опрос сервера IMAP с помощью ImapWorker
, ImapWorker
будет сохранен в пуле ImapMaintainer
как говорят @worker
, Так оно и есть @connections
, @worker
, #polling
, а также #keepalive
, polling
может быть @connections.each
ситуации, или у вас может быть таймер для каждого соединения, добавленный в момент создания соединения.
ImapWorker
есть два метода... один #touch
это поддерживает связь. Основным является #poll
, которая принимает поддерживаемое вами соединение и запускает на нем процесс опроса. Этот метод возвращает информацию или, что еще лучше, сохраняет ее, затем работник возвращается к @worker
бассейн. Это даст вам преимущество того, что процесс опроса будет проходить в отдельном потоке, а не в отдельном волокне, а также позволит исключить наиболее сложный аспект в самом надежном, но в то же время неосознаваемом виде актера.
Работать задом наперед, если ImapRegistry
получает #add
хранит account_info
и дает это ImapMaintainer
который создает соединение и таймеры (но это забывает account_info
и только создает соединение и таймер (ы) или просто создает соединение и позволяет одному большому таймеру поддерживать соединение с @worker
который является бассейном. ImapMaintainer
неизбежно попадает в таймер, поэтому в начале и в конце таймера он может проверить свое соединение. Если по какой-то причине соединение отсутствует, оно может восстановить его с помощью @registry.get
Информация. В рамках заданного по таймеру задания он может выполняться @worker.poll
или же @worker.alive
,
Это иллюстрирует вышеуказанные требования, показывая, как инициализаторы собирают систему акторов, и имеет неполный скелет упомянутых методов.
WORKERS = 9 #de arbitrarily chosen
class ImapRegistry
include Celluloid
def initialize
@maintainer = ImapMaintainer.supervise
@credentials = {}
end
def add( account_info )
...
end
def get( id )
...
end
def remove( id )
...
end
end
class ImapMaintainer
include Celluloid
def initialize
@worker = ImapWorker.pool size: WORKERS
@connections = {}
end
def add( id, credential )
...
end
def remove( id )
...
end
#de These exist if there is one big timer:
def polling
...
end
def keepalive
...
end
end
class ImapWorker
include Celluloid
def initialize
#de Nothing needed.
end
def poll( connection )
...
end
def touch( connection )
...
end
end
registry = ImapRegistry.supervise
я люблю Celluloid
и надеюсь, что у вас есть большой успех с этим. Пожалуйста, спросите, хотите ли вы что-нибудь прояснить, но это, по крайней мере, еще одна стратегия, которую вы должны рассмотреть.