在 Mojolicious 应用程序中,我试图在单击链接时将 ODT 文件转换为 HTML。我使用 shell 命令“soffice”转换文件。转换文件需要一些时间。我向用户发送状态消息以通知他进度。我通过写入 Mojo::Log 对象来发送这些状态更新消息。然后,我在 EventSource 路由中订阅此日志对象。
然后我遍历文件并使用 AnyEvent::Util run_cmd 执行外部“soffice”程序。
for my $file (@{ $filelist }) {
my $output_dir = './output_dir';
my $cmd = "soffice --headless --convert-to html --outdir '$output_dir' '$file'";
my $cv = AnyEvent->condvar;
my $w;
$w = run_cmd($cmd,
'>' => sub { my $out = shift;
&WriteToLog({ status => "cmd output '$out'..." });
undef $w;
$cv->send;
},
'2>' => sub { my $err = shift;
&WriteToLog({ status => "ERROR '$err'..." });
undef $w;
$cv->send;
}
);
$cv->recv;
}
几乎从主要的 AnyEvent 教程中复制和粘贴。如果要转换的文件很少(大约 2 或 3 个),则一切顺利。通过 EventSource 连接发送的状态消息显示在客户端浏览器上。然后在所有文件都被转换后,呈现网页。
如果要处理更多文件,则会转换一些文件,然后出现线程标题中的错误消息。
包含上述代码的路由的路由是这样的:
my $initdocs = $r->under->to('docroute#initdocs');
$initdocs->get('/showdocs')->to('docroute#showdocs');
上面的代码在“initdocs”路径中。
任何帮助表示赞赏。提前致谢。
最佳答案
我认为您要做的是在不阻塞服务器线程的其余部分的情况下调用 soffice(阻塞)进程。我不是 AE 方面的专家,但我认为这不是 run_cmd
做。更接近什么fork_call
确实如此。也许你想要做的更像是这样的:
#!/usr/bin/env perl
use Mojolicious::Lite;
use EV;
use AnyEvent::Util 'fork_call';
any '/' => sub {
my $c = shift;
$c->render_later;
fork_call { `sleep 5 && echo 'hi'` } sub {
my $data = shift;
$c->render( text => $data );
};
};
app->start;
在我的示例中,我只是进行了一个简单的阻塞调用,但您可以轻松调用
soffice
.现在既然你说在返回客户端之前你可能需要转换几个不同的文件,你可能想使用优秀的 Mojo::IOLoop::Delay来管理流程。
#!/usr/bin/env perl
use Mojolicious::Lite;
use EV;
use AnyEvent::Util 'fork_call';
my @jobs = (
q{sleep 5 && echo 'hi'},
q{sleep 5 && echo 'bye'},
);
any '/' => sub {
my $c = shift;
$c->render_later;
my $delay = Mojo::IOLoop->delay;
$delay->on( finish => sub {
shift; $c->render(text => join '', @_ );
});
fork_call { `$_` } $delay->begin(0) for @jobs;
};
app->start;
再一次,我只是捕获输出并将其发送到渲染调用,但请注意它在返回之前等待所有作业完成。更接近您的真实用例的可能是:
#!/usr/bin/env perl
use Mojolicious::Lite;
use EV;
use AnyEvent::Util 'fork_call';
use Capture::Tiny 'capture';
any '/' => sub {
my $c = shift;
my $files = $c->every_param('file');
$c->render_later;
my $delay = Mojo::IOLoop->delay;
$delay->on( finish => sub {
shift; $c->render( json => \@_ );
});
my $output_dir = './output_dir';
for my $file (@$files) {
my $cmd = "soffice --headless --convert-to html --outdir '$output_dir' '$file'";
fork_call { [ capture { system $cmd } ] } $delay->begin(0);
}
};
app->start;
这对作为参数传递给路由的每个文件名运行 soffice (
/?file=myfile&file=otherfile
)。然后 stdout、stderr 和返回代码(应该是,我显然没有运行过这个)作为 json 呈现给客户端(您可以轻松地记录它)。
关于perl - 在 Mojolicious 中使用 AnyEvent run_cmd,我不断收到此错误 : "AnyEvent::CondVar: recursive blocking wait attempted",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19505798/