среда, 9 декабря 2009 г.

[comp.prog.idea] Обновление exe-шника для дочернего процесса

Работаю сейчас над проектом, в котором процесс-менеджер запускает N одинаковых дочерних процессов и распределяет работу между ними. В случае проблем с дочерними процессами (аварийное завершение, например) процесс-менеджер запускает вместо сбойного процесса новый дочерний процесс. При работе под Windows в этой схеме есть неприятная особенность: нельзя изменить exe-файл запущенного процесса. При разработке это проявляется особенно часто – изменяешь что-нибудь в исходнике, запускаешь компиляцию и получаешь в лоб сообщение от линкера о том, что exe-файл не может быть заменен, поскольку процесс-менеджер остался запущенным :) Да и в процессе эксплуатации может потребоваться быстренько заменить exe-шник дочернего процесса новой версией.

Идея проста. В конфигурации процессу-менеджеру указывается имя exe-файла дочернего процесса. Например:

{child_process
  {executable "./trx_processor.exe"}
  {args "..."}
}

Но процесс-менеджер не запускает указанный exe-шник напрямую. Вместо этого он генерирует уникальный идентификатор и формирует на его основе новое уникальное имя exe-файла. Так, вместо trx_processor.exe получается имя, скажем, ./tmp/trx_processor-20091207-190200-102-38452.exe. Исходный exe-файл копируется под новым уникальным именем. И запускается уже новый exe-файл.

Процесс-менеджер запоминает размер и дату/время обновления исходного exe-файла (можно и контрольную сумму подсчитывать). Периодически, по таймеру или при получении новых транзакций, процесс-менеджер проверяет исходный exe-файл. Если его размер или дата/время (или контрольная сумма) изменилась, то процесс-менеджер понимает, что дочерний процесс обновился. Поэтому старые процессы дочерние процессы нужно завершать, а вместо них стартовать новые процессы. При старте новых процессов так же генерируется уникальное новое имя, происходит копирование, сохранение размера и даты/времени исходного exe-файла и т.д.

Так же процесс-менеджер должен периодически удалять уже не нужные exe-файлы с уникальными именами. Хотя этим может заниматься и какой-то внешний скрипт.

Естественно, процесс-менеджер должен быть достаточно умным, чтобы не загадить весь диск уникальными копиями exe-файлов, если их запуск завершается неудачно по какой-то причине.

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

Примечание. В таком виде данная схема будет работать только, если в exe-шник дочернего процесса статически влинкованны все нужные библиотеки. Если же вместе с exe-файлом поставляется набор dll-ек, то ситуация усложняется. В таком случае я бы делал подкаталог с уникальным именем, куда копировал бы exe- и dll-файлы, и оттуда бы уже запускал exe-шник дочернего процесса.

5 комментариев:

Анонимный комментирует...

Вобщем надо организовать reference-counting сборщик мусора, в случае когда reference является рабочим потоком, а мусором - папка на диске :)

eao197 комментирует...

А винда сама такой reference-counting ведет :) Поэтому можно просто регулярно пытаться удалять временные папки с диска. Если из папки запущен exe-шник или загружена dll, то папку удалить не получится :)

Анонимный комментирует...

Как вариант сделать запуск через bat файл, в котором прописан последний exe'шник. При обновлении программы, создавать новый exe с чуть другим именем и менять bat файл (его изменить получться). И дальше рестарт bat'а.

Другой вариант - библиотека с необоходимым функционалом и минимальный exe'шник, который только умеет подгружать библиотеку. Основная программа проверяет появление новой версии библиотеки (или получает команду проверить) и закрывает текущую и подгружает новую. После этого старая версия удаляется.

Rustam комментирует...

Зато никто ни мешает переименовать запущенный exe файл, я замену на ходу так делал. Хотя что в твоем случае удобней не знаю.

eao197 комментирует...

>Зато никто ни мешает переименовать запущенный exe файл, я замену на ходу так делал

Удивительное дело! exe-файл запущенного процесса можно переименовать, но нельзя удалить (ни до, ни после переименования). Не знал о такой фиче винды. Может быть, где-нибудь, когда-нибудь пригодится.