Все задачи

Эх, SOAP, SOAP! Кто тебя выдумал?

29 Apr 2013

В проекте образовался вот такой код:

use SOAP::Lite;

my $soap = SOAP::Lite->service("file:very_useful_service.wsdl");

...

for my $uid (@uids){
    my $data = process_uid($uid);
    eval { $soap->update($uid, $data) },
    write_log("update failed for uid $uid") if $@;
}

На первый взгляд все хорошо… Но в действительности все плохо!

### Подсказка

Показать

Большая часть записей не обновляется, но сообщений в логе нет.

Подсказка-2

Показать

Зато в логе есть предупреждения о записях, которые на самом деле успешно обработаны.

Подсказка-3

Показать

Внимание к мелким деталям – залог успеха.

Разоблачение

Показать

Все дело в запятой вместо точки с запятой. Код следует исправить так:

my $data = process_uid($uid);
-    eval { $soap->update($uid, $data) },
+    eval { $soap->update($uid, $data) };
     write_log("update failed for uid $uid") if $@;

Первоначальный же вариант работает так:

for my $uid (@uids){
    my $data = process_uid($uid);
    if($@){
        eval { $soap->update($uid, $data) };
        write_log("update failed for uid $uid");
    }
}

То есть если к началу цикла переменная $@ была сброшена, то ни одна запись из @uids вообще не будет обработана. Если же к началу цикла переменная $@ оказывается непустой, то метод update будет вызван для нескольких первых элементов массива @uids… Ровно до первого удачного срабатывания. После этого переменная $@ снова станет пустой, и остаток цикла отработает вхолостую.

А в лог попадут записи обо всех записях, которые обрабатываются методом update, независимо от результата. То есть если к началу цикла переменная $@ была пустой, то в лог ничего не попадет. Если же $@ была непустой, то в лог попадут записи о первых нескольких uid’ах – вплоть до первого, на котором update сработает успешно.