Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Системное программирование > Win32::Daemon & WMI Notification Query


Автор: Ramirez 20.10.2011, 21:27
Доброго всем дня!

Обращаюсь к коллективному разуму, работавшему с WMI smile

Есть скрипт слушающий некие события WMI вида:

Код

my $wmi = Win32::OLE->GetObject('winmgmts:{(security)}')->ExecNotificationQuery($wql_query);
while (1) {
    my $event= $wmi->NextEvent(); # тут цикл ждет пока не произойдет событие
    warn "we have event!";  # делаем что-то полезное
}


работает абсолютно линейно, цикл ждет событие, делает что-то и опять ждет.


есть служба на базе Win32::Daemon, вида:

Код

Win32::Daemon::RegisterCallbacks( {
    start       =>  \&Callback_Start,
    running     =>  \&Callback_Running,
    stop        =>  \&Callback_Stop,
    pause       =>  \&Callback_Pause,
    continue    =>  \&Callback_Continue,
} );
Win32::Daemon::StartService( \%CONTEXT, 2000 ); # запустить службу, вызввать &Callback_Running каждые 2 секунды

# -------------------------------------------------------------------
sub Callback_Running {
    my( $event, $context ) = @_;
    if( SERVICE_RUNNING == Win32::Daemon::State() ) {
        warn ('....do something good!');
    }
}


логика работы Win32::Daemon исползует callback'и. 
процедура Callback_Running вызывается каждые 2 секунды, в ней предполагается быстро сделать небольшую часть полезной работы и вернуть управление в Win32::Daemon.
а мне необходимо слушать WMI события.
я не могу в &Callback_Running вызвать прослушивание WMI не заблокировав службу. Она будет обрабатывать мои события, но перестанет  быть управляемой и перестанет отвечать на сигналы Service Control Manager, и он решит что она висит.

как асинхронно обрабатывать события NotificationQuery из WMI?
я пробовал в &Callback_Running делать нечто вида:

Код

my $event = $wmi->NextEvent(500); # подождать события 500 миллисекунд. если события не будет $event будет пустым. 
while ($event ne "") {
    warn ('we have event!'); 
    $event = $wmi->NextEvent(500); # если в течении 500 миллисеккунд не произойдет события выйти из цикла
}


тогда, по идее, код ждет события 500-1000 миллисекунд, если не получает его, то возвращает управление в Win32::Daemon.
но у меня есть основания полагать, что:
-  это неправильный подход и часть событий, происходящих между вызовами &Callback_Running теряется.
- при неудачном стечении обстоятельств/потоке событий он никогда не выйдет из этого цикла



Поделитесь опытом/соображениями.
- как правильно в такой ситуации обрабатывать события NotificationQuery из WMI?
- ExecNotificationQuery() кеширует события если я не успеваю их забирать через NextEvent()?

Автор: Ramirez 10.11.2011, 13:45
Ну что-же, поскольку внятного ответа не нашел, поделюсь своими наблюдениями smile
объект wmi, видимо, всетаки кеширует данные в ожидании вызова NextEvent(). Поэтому имеет смысл всегда вызывать NextEvent() до тех пор, пока оно не вернет пустоту.
Неизвестно, правда, сколько в этот кеш влезает и как посмотреть его состояние.

на основании наблюдений, получился рабочий код вида:

Код

Win32::Daemon::RegisterCallbacks( {
    start       =>  \&Callback_Start,
    running     =>  \&Callback_Running,
    stop        =>  \&Callback_Stop,
    pause       =>  \&Callback_Pause,
    continue    =>  \&Callback_Continue,
} );
Win32::Daemon::StartService( \%CONTEXT, 2000 ); # запустить службу, вызввать &Callback_Running каждые 2 секунды

# -------------------------------------------------------------------
sub Callback_Running {
    my( $event, $context ) = @_;
    if( SERVICE_RUNNING == Win32::Daemon::State() ) {
        my $event;
        while ($event = $wmi->NextEvent(500)) { # если нет события, ждать 500 мсек
            warn('do something!');
        }
    }
}


пока тестирую, но вроде все работает корректно, события не теряются.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)