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
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:
Next, add the Perloku build pack:
Create the git repo and setup on Heroku:
To make everything work, you need a Perloku file to start
hypnotoad
in the foreground. You have to specifyperl
explicity because the shebang line inhypnotoad
refers to the temp location ofperl
when it was built and where it no longer is. Change myapp.pl to whatever you named your application.To get everything installed, you use a standard Makefile.PL. Specify Mojolicious as one of the prerequisites:
Finally, the app itself, which you can create with
mojo
(which calls is myapp.ppl)Here's the generated source:
You have to modify the basic program since hypnotoad needs a bit of configuration (where the default server does not):
Once you have all the files, commit them, and push to the heroku branch.
When you push, a hook will start up everything.
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.