Why is my use of hypnotoad crashing on Heroku? - perl

I'm trying to get hypnotoad with a Mojolicious::Lite app running on Heroku with Perloku. There's something that doesn't happen when hypnotoad gets into its run loop that causes it to crash. I figure I'm missing something simple, but the Heroku docs haven't helped and I haven't been able to coax good error messages out of this.
I start with a very simple application so show some environment variables:
#!/usr/bin/env perl
# today
use Mojolicious::Lite;
get '/' => sub {
my $c = shift;
my $content = "Perl: $^X Pid: $$\n\n";
foreach my $key ( keys %ENV ) {
next unless $key =~ /Mojo|toad/i;
$content .= "$key $ENV{$key}\n";
}
$c->stash( content => $content );
$c->render('index');
};
app->start;
__DATA__
## index.html.ep
% layout 'default';
% title 'Welcome';
<p>Welcome to the Mojolicious real-time web framework!</p>
<pre>
<%= $content %>
</pre>
## layouts/default.html.ep
<!DOCTYPE html>
<html>
<head><title><%= title %></title></head>
<body><%= content %></body>
</html>
When I run this locally, I have no problem. I see from the environment variables that my program is run under hypnotoad:
Welcome to the Mojolicious real-time web framework!
Perl: /Users/brian/Dropbox/bin/perls/perl5.20.0 Pid: 40006
HYPNOTOAD_PID 39981
MOJO_HELP
HYPNOTOAD_TEST
HYPNOTOAD_EXE /Users/brian/bin/perls/hypnotoad5.20.0
MOJO_REUSE 0.0.0.0:8080:6
HYPNOTOAD_REV 3
HYPNOTOAD_APP /Users/brian/Desktop/toady.d/toady
MOJO_MODE production
MOJO_HOME
HYPNOTOAD_STOP
HYPNOTOAD_FOREGROUND
Now, I deploy this with Mojolicious::Command::deploy::heroku:
% toady deploy heroku --create
This is running at https://frozen-brushlands-4002.herokuapp.com, using the default Perloku file:
#!/bin/sh
./toady daemon --listen http://*:$PORT --mode production
This isn't running hypnotoad though, despite some references I've seen that says that's what I should get. The application works, though:
Welcome to the Mojolicious real-time web framework!
Perl: /app/vendor/perl/bin/perl Pid: 3
MOJO_REUSE 0.0.0.0:12270:4
MOJO_HOME
MOJO_HELP
MOJO_MODE production
MOJO_EXE ./toady
I figured I could just change the Perloku file to start hypnotoad:
#!/bin/sh
/app/vendor/perl/bin/perl /app/vendor/perl-deps/bin/hypnotoad toady
hypnotoad starts and almost immediately shuts down with no other log messages:
% heroku logs --app ...
2015-01-04T09:23:36.516864+00:00 heroku[web.1]: Starting process with command `./Perloku`
2015-01-04T09:23:38.321628+00:00 heroku[web.1]: State changed from starting to crashed
I can change the invocation to use the -t to test the app to see if :
#!/bin/sh
/app/vendor/perl/bin/perl /app/vendor/perl-deps/bin/hypnotoad -t toady
That works and I get the "Everything looks good!" message, so hypnotoad is running:
2015-01-04T09:36:36.955680+00:00 heroku[web.1]: Starting process with command `./Perloku`
2015-01-04T09:36:38.340717+00:00 app[web.1]: Everything looks good!
2015-01-04T09:36:39.085887+00:00 heroku[web.1]: State changed from starting to crashed
I turn on Mojo debug logging, but I don't see additional output other than my own statements.
#!/usr/bin/env perl
use Mojolicious::Lite;
$|++;
my $log = app->log;
$log->level( 'debug' );
$log->debug( "INC: #INC" );
get '/' => sub {
...;
};
$log->debug( "Right before start" );
my $app = app->start;
$log->debug( "Right after start" );
$app; # must return application object
I tried other things, such as making it load a module I know is not there and I get the expected "Could not find" error in the logs.
Running from the shell in heroku (heroku run bash) was not illuminating. The output of mojo version is the same as on my local machine:
$ perl vendor/perl-deps/bin/mojo version
CORE
Perl (v5.16.2, linux)
Mojolicious (5.71, Tiger Face)
OPTIONAL
EV 4.0+ (n/a)
IO::Socket::Socks 0.64+ (n/a)
IO::Socket::SSL 1.84+ (n/a)
Net::DNS::Native 0.15+ (n/a)
You might want to update your Mojolicious to 5.72.
I figure there's something really simple that I'm missing, but at the same time, none of this is architected for easy debugging.
Oleg gets a little closer, but there are still problems. I had tried the foreground option before and run into the same problems but failed to mention it.
If I start hypnotoad in the foreground, it tries to bind to an address. It can't bind to port 80 (or 443) and crashes, and it can listen to 127.0.0.1: almost, but it looks like it fails to completely listen:
2015-01-13T11:47:54+00:00 heroku[slug-compiler]: Slug compilation started
2015-01-13T11:48:32+00:00 heroku[slug-compiler]: Slug compilation finished
2015-01-13T11:48:32.735095+00:
00 heroku[api]: Deploy dcab778 by ...
2015-01-13T11:48:32.735095+00:00 heroku[api]: Release v31 created by ...
2015-01-13T11:48:32.969489+00:00 heroku[web.1]: State changed from crashed to starting
2015-01-13T11:48:34.909134+00:00 heroku[web.1]: Starting process with command `./Perloku`
2015-01-13T11:48:36.045985+00:00 app[web.1]: Can't create listen socket: Permission denied at /app/vendor/perl-deps/lib/perl5/Mojo/IOLoop.pm line 120.
2015-01-13T11:48:36.920004+00:00 heroku[web.1]: Process exited with status 13
2015-01-13T11:48:36.932014+00:00 heroku[web.1]: State changed from starting to crashed
Here's with an unprivileged port:
2015-01-13T11:39:10+00:00 heroku[slug-compiler]: Slug compilation started
2015-01-13T11:39:44+00:00 heroku[slug-compiler]: Slug compilation finished
2015-01-13T11:39:44.519679+00:00 heroku[api]: Deploy bbd1f68 by ...
2015-01-13T11:39:44.519679+00:00 heroku[api]: Release v29 created by ...
2015-01-13T11:39:44.811111+00:00 heroku[web.1]: State changed from crashed to starting
2015-01-13T11:39:47.382298+00:00 heroku[web.1]: Starting process with command `./Perloku`
2015-01-13T11:39:48.454706+00:00 app[web.1]: [Tue Jan 13 11:39:48 2015] [info] Listening at "http://*:8000".
2015-01-13T11:39:48.454733+00:00 app[web.1]: Server available at http://127.0.0.1:8000.
2015-01-13T11:39:48.454803+00:00 app[web.1]: [Tue Jan 13 11:39:48 2015] [info] Manager 3 started.
2015-01-13T11:39:48.480084+00:00 app[web.1]: [Tue Jan 13 11:39:48 2015] [info] Creating process id file "/app/hypnotoad.pid".
2015-01-13T11:40:47.703110+00:00 heroku[web.1]: Stopping process with SIGKILL
2015-01-13T11:40:47.702867+00:00 heroku[web.1]: Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch
2015-01-13T11:40:48.524470+00:00 heroku[web.1]: Process exited with status 137
2015-01-13T11:40:48.534002+00:00 heroku[web.1]: State changed from starting to crashed

This is really just a wild guess, but maybe the heroku infrastructure doesn't expect the runner to terminate? If so, you could try to start hypnotoad with --foreground or -f.
Also, you could try to do some logging from inside the application to see if it ever runs it at all.

Oleg answers the question, but there are some pieces missing in the assumptions.
First, create a new heroku app and remember the name of the app:
$ heroku create
Creating vast-spire-6174... done, stack is cedar-14
https://vast-spire-6174.herokuapp.com/ | https://git.heroku.com/vast-spire-6174.git
Next, add the Perloku build pack:
$ heroku config:add BUILDPACK_URL=https://github.com/judofyr/perloku.git
Create the git repo and setup on Heroku:
$ mkdir testapp
$ cd testapp
$ git init
$ heroku git:remote -a vast-spire-6174
To make everything work, you need a Perloku file to start hypnotoad in the foreground. You have to specify perl explicity because the shebang line in hypnotoad refers to the temp location of perl when it was built and where it no longer is. Change myapp.pl to whatever you named your application.
#!/bin/sh
/app/vendor/perl/bin/perl /app/vendor/perl-deps/bin/hypnotoad -f myapp.pl
To get everything installed, you use a standard Makefile.PL. Specify Mojolicious as one of the prerequisites:
use strict;
use warnings;
use ExtUtils::MakeMaker;
WriteMakefile(
VERSION => '0.01',
PREREQ_PM => {'Mojolicious' => '5.72'},
test => {TESTS => 't/*.t'}
);
Finally, the app itself, which you can create with mojo (which calls is myapp.ppl)
$ mojo generate lite_app
Here's the generated source:
#!/usr/bin/env perl
use Mojolicious::Lite;
# Documentation browser under "/perldoc"
plugin 'PODRenderer';
get '/' => sub {
my $c = shift;
$c->render('index');
};
app->start;
__DATA__
## index.html.ep
% layout 'default';
% title 'Welcome';
Welcome to the Mojolicious real-time web framework!
## layouts/default.html.ep
<!DOCTYPE html>
<html>
<head><title><%= title %></title></head>
<body><%= content %></body>
</html>
You have to modify the basic program since hypnotoad needs a bit of configuration (where the default server does not):
#!/usr/bin/env perl
use Mojolicious::Lite;
# Documentation browser under "/perldoc"
plugin 'PODRenderer';
plugin Config => {
default => {
hypnotoad => {
listen => ["http://*:$ENV{PORT}"]
}
}
};
get '/' => sub {
my $c = shift;
$c->render('index');
};
app->start;
__DATA__
## index.html.ep
% layout 'default';
% title 'Welcome';
Welcome to the Mojolicious real-time web framework!
## layouts/default.html.ep
<!DOCTYPE html>
<html>
<head><title><%= title %></title></head>
<body><%= content %></body>
</html>
Once you have all the files, commit them, and push to the heroku branch.
$ git add .
$ git commit -am "make it better"
$ git push heroku master
When you push, a hook will start up everything.
Counting objects: 7, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (7/7), done.
Writing objects: 100% (7/7), 1.14 KiB | 0 bytes/s, done.
Total 7 (delta 0), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Fetching custom git buildpack... done
remote: -----> Perloku app detected
remote: -----> Vendoring Perl
remote: Using Perl 5.18.1
remote: -----> Installing dependencies
remote: --> Working on /tmp/build_a73f24f0619fa2ab299586098c5e8daf
remote: Configuring /tmp/build_a73f24f0619fa2ab299586098c5e8daf ... OK
remote: ==> Found dependencies: Mojolicious
remote: --> Working on Mojolicious
remote: Fetching http://www.cpan.org/authors/id/S/SR/SRI/Mojolicious-5.72.tar.gz ... OK
remote: Configuring Mojolicious-5.72 ... OK
remote: ==> Found dependencies: IO::Socket::IP
remote: --> Working on IO::Socket::IP
remote: Fetching http://www.cpan.org/authors/id/P/PE/PEVANS/IO-Socket-IP-0.36.tar.gz ... OK
remote: Configuring IO-Socket-IP-0.36 ... OK
remote: Building IO-Socket-IP-0.36 ... OK
remote: Successfully installed IO-Socket-IP-0.36
remote: Building Mojolicious-5.72 ... OK
remote: Successfully installed Mojolicious-5.72
remote: <== Installed dependencies for /tmp/build_a73f24f0619fa2ab299586098c5e8daf. Finishing.
remote: 2 distributions installed
remote: Dependencies installed
remote: -----> Discovering process types
remote: Procfile declares types -> (none)
remote: Default types for Perloku -> web
remote:
remote: -----> Compressing... done, 14.1MB
remote: -----> Launching... done, v5
remote: https://vast-spire-6174.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/vast-spire-6174.git
* [new branch] master -> master
The URL of your application shows up toward the end of the output.
Why this was working for me before I don't know. I was letting a mojo command deploy for me, so there could be something to investigate there. However, it's a bit easier to commit and push without the intermediary.

After some testing I found a way to run hypnotoad on heroku
1. Perloku content should looks like this
#!/bin/sh
perl /app/vendor/perl-deps/bin/hypnotoad -f mojocrashtest
Description
First of all we need to explicity call perl. Because
heroku run bash
head /app/vendor/perl-deps/bin/hypnotoad
shows
#!/tmp/perl/perls/perl-5.18.1/bin/perl
eval 'exec /tmp/perl/perls/perl-5.18.1/bin/perl -S $0 ${1+"$#"}'
if 0; # not running under some shell
where /tmp/perl/perls/perl-5.18.1/bin/perl doesn't exists. So, /app/vendor/perl-deps/bin/hypnotoad will not start, but perl /app/vendor/perl-deps/bin/hypnotoad will be ok.
Then we need key -f for hypnotoad as #moritz guessed. Otherwise heroku will think that your app finished unexpectedly.
2. You should start hypnotoad on port $ENV{PORT}
For Mojolicious::Lite you just need to write something like this at the top of your app:
plugin Config => {default => {hypnotoad => {listen => ["http://*:$ENV{PORT}"]}}};
For full app you can do it inside the startup handler.
3. heroku open
And this is a full code of Mojolicious::Lite application
#!/usr/bin/env perl
# today
use Mojolicious::Lite;
plugin Config => {default => {hypnotoad => {listen => ["http://*:$ENV{PORT}"]}}};
get '/' => sub {
my $c = shift;
my $content = "Perl: $^X Pid: $$\n\n";
foreach my $key ( keys %ENV ) {
next unless $key =~ /Mojo|toad/i;
$content .= "$key $ENV{$key}\n";
}
$c->stash( content => $content );
$c->render('index');
};
app->start;
__DATA__
## index.html.ep
% layout 'default';
% title 'Welcome';
<p>Welcome to the Mojolicious real-time web framework!</p>
<pre>
<%= $content %>
</pre>
## layouts/default.html.ep
<!DOCTYPE html>
<html>
<head><title><%= title %></title></head>
<body><%= content %></body>
</html>
heroku logs
2015-01-13T12:08:04.843204+00:00 heroku[web.1]: Starting process with command `./Perloku`
2015-01-13T12:08:06.019070+00:00 app[web.1]: Server available at http://127.0.0.1:13533.
2015-01-13T12:08:06.018899+00:00 app[web.1]: [Tue Jan 13 12:08:06 2015] [info] Listening at "http://*:13533".
2015-01-13T12:08:06.019035+00:00 app[web.1]: [Tue Jan 13 12:08:06 2015] [info] Manager 3 started.
2015-01-13T12:08:06.055437+00:00 app[web.1]: [Tue Jan 13 12:08:06 2015] [info] Creating process id file "/app/hypnotoad.pid".
2015-01-13T12:08:06.412283+00:00 heroku[web.1]: State changed from starting to up
2015-01-13T12:08:08.040072+00:00 heroku[router]: at=info method=GET path="/" host=floating-temple-3676.herokuapp.com request_id=e9f9bb4d-f71f-4b4c-a129-70faf044c38b fwd=194" dyno=web.1 connect=3ms service=34ms status=200 bytes=586
2015-01-13T12:08:08.029819+00:00 app[web.1]: Use of uninitialized value in concatenation (.) or string at /app/mojocrashtest line 13, <DATA> line 39.
2015-01-13T12:08:08.029836+00:00 app[web.1]: Use of uninitialized value in concatenation (.) or string at /app/mojocrashtest line 13, <DATA> line 39.
2015-01-13T12:08:08.029839+00:00 app[web.1]: Use of uninitialized value in concatenation (.) or string at /app/mojocrashtest line 13, <DATA> line 39.
2015-01-13T12:08:08.029842+00:00 app[web.1]: Use of uninitialized value in concatenation (.) or string at /app/mojocrashtest line 13, <DATA> line 39.
URL for my app: http://floating-temple-3676.herokuapp.com/
BTW, I didn't use mojo deploy, just git

Related

Can't use an array as a reference when installing perl module

edit: worked with sudo cpanm Data::Match --force
I'm trying to install the "Data::Match" perl module with ubuntu 18.04.
I use:
perl Makefile.pl
make
make test
And I get the following error:
make test
PERL_DL_NONLAZY=1 "/usr/bin/perl" "-Iblib/lib" "-Iblib/arch" test.pl
1..1
# Running under perl version 5.026001 for linux
# Current time local: Wed Jun 29 18:41:13 2022
# Current time GMT: Wed Jun 29 15:41:13 2022
# Using Test.pm version 1.30
Can't use an array as a reference at blib/lib/Data/Match.pm line 968.
Compilation failed in require at test.pl line 10.
BEGIN failed--compilation aborted at test.pl line 10.
Makefile:825: recipe for target 'test_dynamic' failed
make: *** [test_dynamic] Error 255
I installed many other modules and they all worked perfectly fine.
I also tried installing with
perl -MCPAN -e shell
and that didn't help.
What should I do?
The Data::Match module has some syntax that Perl v5.22 tightened up. That's why it fails. Note that force installing a module with an egregious problem like that means it will just fail when you run your program.
If you can, don't use this module. I have no idea what it does, so I don't have any suggestions for a replacement.
Let's suppose you need this module for whatever reason, even though it's 20 years old. Perhaps you're supporting a legacy app that you just need to get working.
There's this line (L968) which dereferences an array element that is itself an array reference:
$str .= $sep . '{' . join(',', #$ind->[0]) . '}';
That should be the circumfix notation to delimit the reference part:
$str .= $sep . '{' . join(',', #{$ind->[0]}) . '}';
If you make that change to Match.pm before you run perl Makefile.PL, the tests pass (but with a warning) and you can install the module.
If that's all you need, you can stop here.
Distroprefs
CPAN.pm has a way to handle these situations so you don't have to make the change every time that you want to install the module. Before CPAN.pm does its work, it can patch the problem distribution, suggest a replacement distro, or many other things. You do this with "distroprefs". There are many examples in the CPAN.pm repo.
There are a few things to set up. First, set up your distroprefs directory (o conf init prefs_dir). Second, configure a directory to hold you patches (o conf patches_dir). I choose patches under my .cpan directory, but it can be anything. Save your changes before you exit.
% cpan
% cpan[1]> o conf init prefs_dir
Directory where to store default options/environment/dialogs for
building modules that need some customization? [/Users/brian/.cpan/prefs]
% cpan[2]> o conf patches_dir /Users/brian/.cpan/patches
% cpan[3]> o conf commit
distroprefs have two parts. The first specifies what you want to happen. This can be a YAML, Storable, or Data::Dumper file. If YAML (which most people seem to use), then you need to install the YAML module first.
Here's a simple distroprefs file. It tells CPAN.pm how to match a distribution as you'd see it on CPAN (AUTHOR/FILE). In this example, it's action is patches, which is an array of patch files. Since you set up patches_dir, that's where it will look. The file name for the patch isn't special, and it can be compressed. I chose the distro name, my name as the person who patched it, then .patch.
---
match:
module: "Data::Match"
distribution: "^KSTEPHENS/Data-Match-0.06.tar.gz"
patches:
- Data-Match-0.06-BDFOY-01.patch
Here's your patch. Back up the original file, change the target file, then get the unified diff (or whatever your patch understands):
$ diff -u Match.pm.orig Match.pm
--- Match.pm.orig 2022-06-29 15:04:06.000000000 -0400
+++ Match.pm 2022-06-29 14:55:45.000000000 -0400
## -965,7 +965,7 ##
elsif ( $ref eq 'HASH' ) {
if ( ref($ind) eq 'ARRAY' ) {
# Not supported by DRef.
- $str .= $sep . '{' . join(',', #$ind->[0]) . '}';
+ $str .= $sep . '{' . join(',', #{$ind->[0]}) . '}';
} else {
$str .= $sep . $ind;
}
But you want this in your patches dir with the name that you specified, so redirect the output there:
$ diff -u Match.pm.orig Match.pm > /Users/brian/.cpan/patches/Data-Match-0.06-BDFOY-01.patch
If you want to get really fancy, you could put that patches directory in an environment variable in your profile so you don't have to remember it:
$ diff -u Match.pm.orig Match.pm > $CPAN_PATCHES_DIR/Data-Match-0.06-BDFOY-01.patch
Now when you try to install Data::Match with cpan, it knows that it's installing Data-Match-0.06, it matches that distro from a distroprefs file, and that distroprefs file tell CPAN.pm to perform an action. In this case, it needs to find the patch file and apply it. After the patch is applied, the tests pass and the installation succeeds:
% cpan Data::Match
Reading '/Users/brian/.cpan/Metadata'
Database was generated on Wed, 29 Jun 2022 05:56:00 GMT
Running install for module 'Data::Match'
______________________ D i s t r o P r e f s ______________________
Data-Match-0.06-BDFOY-01.yml[0]
Checksum for /Users/brian/.cpan/sources/authors/id/K/KS/KSTEPHENS/Data-Match-0.06.tar.gz ok
Applying 1 patch:
/Users/brian/.cpan/patches/Data-Match-0.06-BDFOY-01.patch
/usr/bin/patch -N --fuzz=3 -p0
patching file Match.pm
Configuring K/KS/KSTEPHENS/Data-Match-0.06.tar.gz with Makefile.PL
Checking if your kit is complete...
Looks good
Generating a Unix-style Makefile
Writing Makefile for Data::Match
Writing MYMETA.yml and MYMETA.json
KSTEPHENS/Data-Match-0.06.tar.gz
/usr/local/perls/perl-5.36.0/bin/perl Makefile.PL -- OK
Running make for K/KS/KSTEPHENS/Data-Match-0.06.tar.gz
cp Match.pm blib/lib/Data/Match.pm
cp lib/Sort/Topological.pm blib/lib/Sort/Topological.pm
Manifying 2 pod documents
KSTEPHENS/Data-Match-0.06.tar.gz
/usr/bin/make -- OK
Running make test for KSTEPHENS/Data-Match-0.06.tar.gz
PERL_DL_NONLAZY=1 "/usr/local/perls/perl-5.36.0/bin/perl" "-Iblib/lib" "-Iblib/arch" test.pl
1..1
# Running under perl version 5.036000 for darwin
# Current time local: Wed Jun 29 15:54:13 2022
# Current time GMT: Wed Jun 29 19:54:13 2022
# Using Test.pm version 1.31
ok 1
PERL_DL_NONLAZY=1 "/usr/local/perls/perl-5.36.0/bin/perl" "-MExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
t/t1.t .. ok
t/t2.t .. ok
t/t3.t .. 1/15 splice() offset past end of array at /Users/brian/.cpan/build/Data-Match-0.06-15/blib/lib/Data/Match.pm line 1941.
t/t3.t .. ok
t/t4.t .. ok
All tests successful.
Files=4, Tests=182, 0 wallclock secs ( 0.03 usr 0.01 sys + 0.18 cusr 0.04 csys = 0.26 CPU)
Result: PASS

How to correctly display messages in console?

I use mojolicious application. When I do logging all if fine, except when I run application under morbo I see text like:
$app->log->info('тест лога');
[Sat Oct 6 15:22:43 2018] [info] �е�� лога
here is some problem with utf8.
What should I do that messages will be correctly displayed?
My terminal have support for utf8. I run Linux Mint v19.3
Here is how messages looks which come from script:
Test terminal:
Don't use the following when using Mojo::Log to write to STDERR:
binmode STDERR, ':encoding(UTF-8)';
Mojo::Log explicitly encodes everything it logs using UTF-8, even when writing to STDERR.
sub append {
my ($self, $msg) = #_;
return unless my $handle = $self->handle;
flock $handle, LOCK_EX;
$handle->print(encode('UTF-8', $msg)) or croak "Can't write to log: $!";
flock $handle, LOCK_UN;
}
When using STDERR as the log output (the default), this conflicts with the well-established practice of adding an encoding layer to STD*. In such a circumstance, double-encoding occurs.
One must therefore avoid doing
binmode STDERR, ':encoding(UTF-8)';
Note that this is done as part of
use open ':std', ':encoding(UTF-8)';
Try to run following code sample in your system. The test confirmed with correct UTF-8 output in terminal
#!/usr/bin/env perl
use Mojolicious::Lite -signatures;
get '/' => sub ($c) {
$c->render(text => 'Hello World!');
};
app->log->info('тест лога');
app->start;
Run as morbo test.pl produces following output
:u99257852:~/work/perl/mojo$ morbo ./test.pl
Web application available at http://127.0.0.1:3000
[2020-10-31 13:33:57.42056] [83940] [info] тест лога
[2020-10-31 13:35:16.72465] [83940] [debug] [hga9Tgyy] GET "/"
[2020-10-31 13:35:16.72528] [83940] [debug] [hga9Tgyy] Routing to a callback
[2020-10-31 13:35:16.72574] [83940] [debug] [hga9Tgyy] 200 OK (0.001078s, 927.644/s)
(uiserver):u99257852:~/work/perl/mojo$
Tested locally with nc localhost 3000
(uiserver):u99257852:~$ nc localhost 3000
GET / HTTP/1.1
HTTP/1.1 200 OK
Date: Sat, 31 Oct 2020 17:35:16 GMT
Server: Mojolicious (Perl)
Content-Type: text/html;charset=UTF-8
Content-Length: 12
Hello World!
Output of uname -a
(uiserver):u99257852:~/work/perl/mojo$ uname -a
Linux infongwp-us19 4.4.223-icpu-044 #2 SMP Sun May 10 11:26:44 UTC 2020 x86_64 GNU/Linux
(uiserver):u99257852:~/work/perl/mojo$
Bash is user's shell configured with ~/.bashrc with following settings to support UTF-8
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8:

WWW::Mechanize::PhantomJS code in Mojolicious Lite script doesn't work when running in background mode

I have this very simple Mojolicious Lite script:
#!/usr/bin/env perl
use v5.10;
use WWW::Mechanize::PhantomJS;
use Mojolicious::Lite;
my $mech = WWW::Mechanize::PhantomJS->new();
$mech->get('http://stackoverflow.com/');
get '/test' => sub {
my $c = shift;
$mech->get("https://stackoverflow.com/questions");
$c->render(template => 'activity');
};
app->secrets(['test secret']);
app->start;
__DATA__
## activity.html.ep
<!DOCTYPE html>
<html>
<head><title>Test</title></head>
<body><h2>Test</h2></body>
</html>
When I start it using hypnotoad in foreground mode (hypnotoad -f ./script.pl), and access /test url -- I get my test page, and clean logs:
[Fri Dec 11 18:00:23 2015] [info] Listening at "http://*:8080"
[Fri Dec 11 18:00:23 2015] [info] Manager 3011 started
[Fri Dec 11 18:00:23 2015] [info] Creating process id file "/home/username/pc_activity/demo_site/hypnotoad.pid"
When I start it using background mode (hypnotoad ./script.pl), and access /test url -- I get "something went very wrong" error page with throwing up raptor.
[Fri Dec 11 17:58:07 2015] [info] Listening at "http://*:8080"
[Fri Dec 11 17:58:07 2015] [info] Manager 2964 started
[Fri Dec 11 17:58:07 2015] [info] Creating process id file "/home/username/pc_activity/demo_site/hypnotoad.pid"
[Fri Dec 11 17:58:14 2015] [error] Error while executing command: get: Server returned error message Can't connect to localhost:8910
Connection refused at /usr/local/share/perl/5.18.2/LWP/Protocol/http.pm line 47, <DATA> line 49.
instead of data at /usr/local/share/perl/5.18.2/Selenium/Remote/Driver.pm line 310.
It turns out the localhost:8910 is default settings for PhanomJS to run at in webdriver mode. Which it isn't on my machine. But even if I start it, and then access the URL, I still get an error:
[Fri Dec 11 18:41:01 2015] [error] Error while executing command: get: Server returned error message Variable Resource Not Found - {"headers":{"Accept":"application/json","Connection":"TE, close","Content-Length":"45","Content-Type":"application/json; charset=utf-8","Host":"localhost:8910","TE":"deflate,gzip;q=0.3","User-Agent":"libwww-perl/6.15"},"httpVersion":"1.1","method":"POST","post":"{\"url\":\"https://stackoverflow.com/questions\"}","url":"/session/98799e80-a060-11e5-8907-0b365878087d/url","urlParsed":{"anchor":"","query":"","file":"url","directory":"/session/98799e80-a060-11e5-8907-0b365878087d/","path":"/session/98799e80-a060-11e5-8907-0b365878087d/url","relative":"/session/98799e80-a060-11e5-8907-0b365878087d/url","port":"","host":"","password":"","user":"","userInfo":"","authority":"","protocol":"","source":"/session/98799e80-a060-11e5-8907-0b365878087d/url","queryKey":{},"chunks":["session","98799e80-a060-11e5-8907-0b365878087d","url"]}} instead of data at /usr/local/share/perl/5.18.2/Selenium/Remote/Driver.pm line 310.
I guess, I don't understand, why does it run in foreground mode, and not in background mode. And then, what can I do to make it run in background mode?
The reason it will not run in background mode is because of threading. After you start hypnotoad in background it spawns some processes.
664161507 46028 1 0 10:34AM ?? 0:00.01 script.pl
664161507 46029 46028 0 10:34AM ?? 0:00.08 script.pl
664161507 46030 46028 0 10:34AM ?? 0:00.01 script.pl
664161507 46031 46028 0 10:34AM ?? 0:00.01 script.pl
664161507 46032 46028 0 10:34AM ?? 0:00.01 script.pl
These will not have access to the PhantomJS you created in the parent process. I didn't look into how this communication is done, but if you want to share PhantomJS for your workers you need to make it a separate service.
If you however want to have a PhantomJS for each request you can initialize it in the request, but I don't necessarily encourage this approach:
get '/test' => sub {
my $c = shift;
my $mech = WWW::Mechanize::PhantomJS->new();
$mech->get('http://stackoverflow.com/');
$mech->get("https://stackoverflow.com/questions");
$c->render(template => 'activity');
};

trouble installing MozRepl

I've been trying to install WWW::Mechanize::Firefox through CPAN and I am having trouble installing the dependency MozRepl. The installation goes through but the tests all fail, and when I force install it and run my perl script, I run into an error
Failed to connect to , at /Library/Perl/5.12/MozRepl/RemoteObject.pm line 467.
SO I uninstalled MozRepl and looked at the tests I get the following errors in the log:
# Failed test at t/10-plugin-repl-enter.t line 11.
Can't locate object method "repl_enter" via package "MozRepl" at t/10-plugin-repl-enter.t line 12.
...
# Failed test at t/20-plugin-json.t line 16.
Can't locate object method "json" via package "MozRepl" at t/20-plugin-json.t line 17.
# Failed test at t/19-plugin-repl-util-doc_for.t line 14.
Can't locate object method "repl_doc_for" via package "MozRepl" at t/19-plugin-repl-util-doc_for.t line 16.
# Failed test at t/18-plugin-repl-util-help_url_for.t line 14.
Can't locate object method "repl_help_url" via package "MozRepl" at t/18-plugin-repl-util-help_url_for.t line 16.
etc..
I am running on Mac OSX 10.8.4, 4 GB Ram 2.5 Ghz, Perl version 5.12. Does anybody have any idea what is causing these errors?
UPDATE:
i reinstalled mozrepl, and now I get this error when i run my script:
Failed to connect to , problem connecting to "localhost", port 4242: Connection refused at /Users/thui/perl5/perlbrew/perls/perl-5.16.0/lib/site_perl/5.16.0/MozRepl/Client.pm line 144
This works for me with perl 5.10 or later, latest Firefox (26 as of writing) and Mozrepl from github.
At command propmpt:
(1) Download MozRepl and build the XPI file (Firefox extension):
git clone git://github.com/bard/mozrepl
cd mozrepl
zip -r ../mozrepl.zip *
cd ..
mv mozrepl.zip mozrepl.xpi
(2) Install the extension in Firefox via about:addons [Install from file].
In Firefox:
(3) Menu->Tools->Mozrepl->Activate On Startup
(4) Menu->Tools->Mozrepl->Start
At command propmpt:
(5) which firefox
Make sure the firefox executable (or your OS's wrapper script) is in $PATH - you should get some output!
(6) cpanm WWW::Mechanize::Firefox
(7) Test it!
At this point, if CPANminus reports no errors then WWW::Mechanize::Firefox should be working. The first example from the synopsis is a good test:
#!/usr/bin/perl
use WWW::Mechanize::Firefox;
my $mech = WWW::Mechanize::Firefox->new();
$mech->get('http://google.com');
That assumes MozRepl is listening on port 4242 (check in Menu->Tools->Mozrepl->Change Port). You can also change the port from the perl side; see options for ->new().
(8) cpanm HTML::Display::Common
I found that bcat.pl from the examples required this module, but it wasn't installed as a dependency.

Start the session bus of DBus with Perl Net::DBus

I am using Perl and the Net::DBus module. I wrote a simple test program:
#!/usr/bin/perl
use strict;
use warnings;
package MyObj;
use Net::DBus::Exporter qw(org.example.Tao);
use base qw(Net::DBus::Object);
sub new {
my $class = shift;
my $service = shift;
my $self = $class->SUPER::new($service, '/MyObj');
bless $self, $class;
return $self;
}
dbus_method("Hello", ["string"]);
sub Hello {
return 'Hello';
}
package main;
use Net::DBus;
use Net::DBus::Reactor;
my $bus = Net::DBus->session;
my $service = $bus->export_service("org.example.Tao");
my $object = MyObj->new($service);
my $reactor = Net::DBus::Reactor->main();
$reactor->run();
return 0;
I am connecting by ssh and using:
Perl, v5.8.8 built for x86_64-linux-thread-multi
Linux example.com 2.6.32.19-0.2.99.17.22250fd-xen #1 SMP 2010-09-13 10:16:50 +0200 x86_64 x86_64 x86_64 GNU/Linux
CentOS release 5.4 (Final)
When I try to start my test.pl, I get the error:
org.freedesktop.DBus.Error.Spawn.ExecFailed:
Failed to execute dbus-launch to autolaunch D-Bus session
This error is raised by this line:
my $bus = Net::DBus->session;
Google hinted to me about dbus-launch. I executed yum install dbus-x11.
I try start my test code again and get error in the same line:
org.freedesktop.DBus.Error.Spawn.ExecFailed:
dbus-launch failed to autolaunch D-Bus session:
Autolaunch error: X11 initialization failed.
After read manuals, I detect that DBUS session daemon isn't started and my ENV var DBUS_SESSION_BUS_ADDRESS is empty:
[root#zion perl]# ps ax|grep dbus|grep -v grep
1019 ? Ss 0:00 dbus-daemon --system
Then I exec:
[root#zion perl]# dbus-launch --sh-syntax
DBUS_SESSION_BUS_ADDRESS='unix:abstract=/tmp/dbus-smHadq6yxV,guid=101ccd74fb75ae501485ed004e2a9043';
export DBUS_SESSION_BUS_ADDRESS;
DBUS_SESSION_BUS_PID=5037;
[root#zion perl]# ps ax|grep dbus|grep -v grep
1019 ? Ss 0:00 dbus-daemon --system
5037 ? Ss 0:00 /bin/dbus-daemon --fork --print-pid 4 --print-address 6 --session
But DBUS_SESSION_BUS_ADDRESS is same empty.
Question:
I need simple two Perl apps. The first app registers the dbus session service. Another app using my registered service. What is the best and correct way to do it in my environment?
First of all, you need to eval dbus-launch output. Like this:
$ env | grep DBUS
(empty output; no DBUS session bus launched yet)
$ eval `dbus-launch --sh-syntax`
(empty output; DBUS session bus started, output is evaluated to set shell vars)
$ env | grep DBUS
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-ZkMjn6B47b,guid=85b2da814a8a061d4e7a55004e35b499
Second, you should consider how are you going to use your apps. Try to answer yourself these questions: why are you trying to bind to session bus (which is by definition a bus, associated with an interactive user session)? If this is a system-wide service, it should bind to system bus. If it is a user service, user session manager should take care of starting dbus session bus.