PHP on Cowboy Web Server – Give It a Shot

In previous post, I gave some background to making PHP run on Cowboy web server. In this post, I’m going to provide technical details how to run your own setup. But it’s really not complicated at all. So, let’s install, run and play with unix1/cowboy_fcgi.

Prerequisites

  • Erlang (19.0 or newer) installed
    • on Linux use your distro’s package manager or download binary from Erlang Solutions
    • on MacOS run brew install erlang
  • GNU make and git in your path
  • php-fpm is in your path
    • on Linux it might be in /usr/sbin/php-fpm

Steps

$ git clone https://github.com/unix1/cowboy_fcgi.git

$ cd cowboy_fcgi/examples/cowboy_php_hello

$ make run

Enjoy

With your browser go to http://localhost:33080/hello.php – you should see the output from the hello.php script.

Modify or add more PHP files

Your currently running application release is located in _rel/cowboy_php_hello_release/lib/cowboy_php_hello-0.1.0/priv/www relative to your current working directory. In that directory you’ll find the hello.php file that produced the output to the browser. You can modify that file, or add more files in that directory.

Change php-fpm configuration

The example includes a php-fpm.conf file in priv/conf/php-fpm.conf. When starting the application, it starts php-fpm with that configuration file. You can modify it prior to building and running the application. For example, try increasing max_children setting from 5 to some other number.

What happened behind the scenes

When make run executed, the following happened:

  • dependencies were fetched
  • Erlang project was compiled and release made
  • released application was started, which, in turn
  • started the php-fpm

Given this, to fully stop both the Erlang application and php-fpm, you could either:

  • hit Ctrl-C twice in Erlang application prompt and manually kill all php-fpm processes; OR
  • type application:stop(cowboy_php_hello). and press enter in the Erlang prompt and then exit out of it

Try more things

Run your own php-fpm

For the sake of simplicity, this example by default started the php-fpm processes for you. But maybe typically you wouldn’t want to do that – instead, you might want to start php-fpm separately as a service. You can do this, and then in src/cowboy_php_hello_app.erl replace this line

cowboy_php_hello:start_with_phpfpm(33080, 33000),

with

cowboy_php_hello:start(33080, 33000),

And replace 33000 with whatever port you ran your php-fpm service on.

Add your own Cowboy handlers

One of the exciting parts of this setup is that you can host both PHP and Erlang applications under one web server. The example project only includes one Cowboy dispatch rule that routes all incoming HTTP requests to the cowboy_fcgi handler. However, this doesn’t need to be the case. You can add your own routing rules to route specific requests to specific handlers, allowing you to have mixed Erlang and PHP environment for your web applications!

Feedback

Try it out, play around with it, and give me feedback. I’d love to hear about use cases, issues, or other thoughts.

PHP on Cowboy Web Server – The Update

Background

Cowboy is an awesome web server – it’s simple, small, fast, standards compliant, and highly scalable. It also provides easy ways to get started with RESTful web applications. Its downside is that, unlike with Apache, nginx, and other more mainstream servers, it’s only usable in Erlang (and related BEAM languages) environments.

There used to be a couple of projects long time ago (2011!) that added FCGI handler module for Cowboy version 0.4, but they were never really maintained beyond the initial release. They quickly became incompatible with rapid development of Cowboy.

Current work

Now that the modern version of Cowboy is 2.0 (as of this writing), I decided took take a stab at updating those 2 projects to work with it. And here’s the result:

https://github.com/unix1/cowboy_fcgi

There are enough quick start steps and examples in that repo to get most developers experimenting. Regardless, in the next post, I’ll go deeper into how one can play around with this setup in greater detail.

How to Set Up Erlang Common Test for Code Coverage

Common Test code coverage and usage is documented here and here, but:

  • there are no examples given
  • documentation fails to state what the minimum required configuration is to turn on code coverage
  • the implementation has no sane defaults and by default code coverage is disabled

So, here’s the minimum sane default:

  • create a cover.spec file in your application directory with the following contents
    {incl_app, my_app, details}.
    {excl_mods, my_app, [my_app_SUITE]}.

    where my_app and my_app_SUITE are names of your application and the test suite(s) you have
  • when running using ct_run, make sure to
    • either specify -cover cover.spec option; OR
    • add this line to your main CT spec file
      {cover, "cover.spec"}.

That’s it! Next time you run CT you should have a nice code coverage report generated with it.

Oh, also, it’s probably worth mentioning that I couldn’t get erlang.mk to run ct_run with the -spec option, so I manually added it in the CT_RUN command.

Elastic Applications in Erlang

How realistic or useful are elastic applications in general, or specifically in Erlang? To demonstrate, I start with Joe Armstrong’s favorite Erlang program – the universal server:

universal_server() ->
    receive
        {become, F} ->
            F()
    end.

Once spawned, it sits and waits until it gets an instruction to become something. Then it becomes that thing it’s told to be.

First, this is really cool. Second, we should expand a bit:

  • make the wrapping process loop
  • optionally make the internal function loop
  • if internal function receives messages, make it respect an “abort” message which would make it stop executing and return the control back to its parent

So, blah blah – all of the above is only few lines of code in Erlang. I’ll call this module gen_node and the gen_node.erl file is as follows:

-module(gen_node).
-export([start/0]).

start() ->
    receive
        {become, F} ->
            F(),
            start();
        reset ->
            start();
        stop ->
            ok
    end.

and then the way we invoke it would be:

1> c(gen_node).
{ok,gen_node}
2> N = spawn(gen_node, start, []).
<0.40.0>

OK, the process is spawned and waiting, let’s give it something to do. Let’s define 2 functions: one that doubles the given number, and another that squares it. They both communicate via messages:

3> Double = fun Double() ->
    receive
      reset -> ok;
      {From, Args} -> From ! Args+Args, Double()
    end
   end.
#Fun<erl_eval.44.106461118>
4> Square = fun Square() ->
    receive
      reset -> ok;
      {From, Args} -> From ! Args*Args, Square()
    end
   end.
#Fun<erl_eval.44.106461118>

Now, let’s tell the spawned process to become “Double”, then reset it and tell it to become “Square”:

5> N ! {become, Double}.
{become,#Fun<erl_eval.44.106461118>}
6> N ! {self(), 16}.
{<0.33.0>,16}
7> flush().
Shell got 32
ok
8> N ! reset.
reset
9> N ! {become, Square}.
{become,#Fun<erl_eval.44.106461118>}
10> N ! {self(), 16}.
{<0.33.0>,16}
11> flush().
Shell got 256
ok

So, this is cool because now we have a generic computing node that we can tell to transform into any arbitrary processor and communicate to it via messages.

Now, finally, let’s wrap this up in an OTP application using gen_server so the worker processes are also supervised:

https://github.com/unix1/gen_node

Now the interaction becomes:

1> Double = fun Double() ->
    receive
      {_, reset} -> ok;
      {From, Args} -> From ! Args+Args, Double()
    end
   end.
#Fun<erl_eval.44.106461118>
2> Square = fun Square() ->
    receive
      {_, reset} -> ok;
      {From, Args} -> From ! Args*Args, Square()
    end
   end.
#Fun<erl_eval.44.106461118>
3> application:start(gen_node).
ok
4> {ok, N, _} = gen_node:start_server().
{ok,<0.42.0>,#Ref<0.0.0.45>}
5> gen_node:become(N, Double).
ok
6> gen_node:send(N, 16).
32
7> gen_node:reset(N).
ok
8> gen_node:become(N, Square).
ok
9> gen_node:send(N, 16).
256

It worked!

So, what’s next?

This is obviously just a concept code. To be usable something needs to track the states and types of nodes, and something else to intelligently control what they are doing and how the behavior should adapt. Possibilities could include:

  • predicting application-specific demand and adjusting resources: e.g. queue X is filling up, while queue Y processes are waiting too long – so make an adjustment in real-time
  • defining capacities of systems by giving different weights to each type of operation, or calculating resources needed to make certain computations
  • more fully using existing resources, or distributing load where the right resources are available

Questions: is this applicable and interesting? Boring? Already been done? Do you have any ideas which direction this should take?

Any constructive feedback is fully welcome.

PHP Sessions in Erlang Mnesia

Motivation

  • create a very simple first Erlang/OTP application
  • link to conventional web development

I decided one of the simplest things to do would be to create a session storage for PHP in Mnesia. But that, in doing so, I would also create an extremely simple key value store wrapper around Mnesia which would track access times.

Disclaimer

Do NOT use this in production, or anywhere where it’s important. If you do, you’re crazy because:

  • it has not been tested in production or production-like environment
  • as I mentioned, this is my first Erlang application
  • connection is made to a single Erlang node, and there is no failover mechanism if that fails
  • session garbage collection is not implemented

Good Stuff

OK, the disclaimer is out of the way, let’s get to the good stuff! Here’s what I did and how.

Tools used

  • Erlang runtime and development headers
  • PHP >=5.3 (>=5.4 preferred) binary and development headers
  • Apache
  • mypeb
  • kvstore
  • lib360

Architecture

[ PHP ] <–> [ mypeb ] <–> [ Erlang ] <–> [ kvstore ] <–> [ Mnesia ]

Instructions

  • download and install prerequisites as best done in your environment
    • Erlang runtime and development headers
    • Apache
    • PHP >=5.3 binary and development headers
  • download and compile mypeb
    • git clone git://github.com/videlalvaro/mypeb.git
    • cd mypeb
    • phpize
    • ./configure
    • make
    • sudo make install
    • php -m | grep peb
    • Note 1: the last command is a test to verify peb module loads successfully
    • Note 2: you might need to specify --with-erllib and --with-erlinc options with ./configure command if they are not automatically found
  • download, compile and run kvstore
  • download lib360
    • git clone git@github.com:unix1/spoof.git
  • add sample PHP script to your web server and test everything
    • download sample gist
    • replace the path in require_once() to wherever you downloaded lib360
    • replace the your-erlang-cookie-here with the contents of ~/.erlang.cookie file
    • access the file through the web server and have fun!

Missing

These are things that I thought of but didn’t bother implementing that I might someday add:

  • make kvstore more configurable and easy to install/start/stop
    • kvstore currently fails to stop (you have to abort)
    • it could use rebar and more automated scripts instead of manual commands
    • support for configurable multiple table names
    • make access time tracking optional
    • implement other storage backends
  • account for failover when primary node connection fails from PHP
  • PHP session garbage collection
  • implement kvstore access through lib360 database layer

Suggestions/Contributions/Feedback

If you have any feedback, feel free to give it via github, blog comments, etc. as appropriate. Enjoy!