1. A FRAMEWORKLESS
APPLICATION AND WHY
WE DID IT
HOW WE BUILT
BONUS: SHORT GUIDE TO PROCESS FORKING,
SIGNALS HANDLING AND MORE
Maksym Bodnar
maksym.bodnar@gmail.com
2. DEFINITION FROM WIKI
WHAT IS A FRAMEWORK
A software framework is an abstraction in which software providing
generic functionality can be selectively changed by additional user-
written code, thus providing application-specific software.
Key features:
• Inversion of control - overall program flow is controlled by a framework, not by
a developer.
• Extensibility - developer can add or override some parts of the framework to
customize it.
• Non-modifiable part - developer usually is not supposed to modify the code of
the framework
3. WHY WE NEED THEM
WHAT IS A FRAMEWORK
Main purpose of any software framework is to facilitate development
by allowing programmers to devote their time to meeting software
requirements rather than dealing with low level standard operations
and focus on writing application specific code [wiki].
To achieve those goals frameworks provide:
• Pre-built components and libraries;
• Autoloading mechanism;
• CLI Tools (zf, artisan etc).
5. SUMMARY
FRAMEWORK VS FRAMEWORK LESS
Framework pros:
• Execution flow, app “skeleton”;
• Bootstrapping, configuration
loading;
• Tools (classes templates, DB
migrations etc) and fancy helper
functions;
Framework cons:
• Execution flow is enforced;
• Unnecessary overhead/complexity;
• Dependency on framework
maintainers.
Frameworkless pros:
• No enforced execution flow;
• No overhead;
• Way greater flexibility.
Frameworkless cons:
• More typing needed (but it is not
that difficult);
• No tools and no fancy helper
functions;
6. BUILDING CLI APP: WHERE TO BEGIN
FRAMEWORKLESS
Key word: composer.
Libraries/components we are going to use:
• Container component (for dependencies injection): pimple/pimple;
• Simple lib for loading variables from a config file into $_ENV structure:
vlucas/phpdotenv;
• A library needed to talk to MongoDB (ughhhh): mongodb/mongodb;
• Decrypting cron expressions (needed for scheduler): mtdowling/cron-
expression;
• Nice dates/time handling: nesbot/carbon;
• Working with RabbitMQ: php-amqplib/php-amqplib;
• Sending emails: swiftmailer/swiftmailer;
• Testing: phpunit/phpunit.
7. BUILDING CLI APP: WHAT IS IN THE CORE
App.php
Application core
• Init container;
• Fill it with different useful
things;
FRAMEWORKLESS
8. BUILDING CLI APP: INITIALIZE EVERYTHING
FRAMEWORKLESS
Bootstrapping the app:
• Create container;
• Load configs;
• Init DB handlers and logger
bootstrap.php
9. It is not that difficult, really…
FRAMEWORKLESS
BUILDING CLI APP: INITIALIZE EVERYTHING
Mock some useful
Laravel functions:
• app();
• config();
• env();
10. STARTING A NEW PROCESS
LET’S FORK
PROCESS PID#111
$pid = pcntl_fork();
PROCESS PID#111
Parent
PROCESS PID#112
Child
$pid ==112 $pid == 0
11. WHAT’S GOING ON HERE
LET’S FORK
• New completely independent process is forked from the existing
one;
• New process is exact copy of the existing one: all variables,
references, handlers are copied
(parentChildShutdownDemo.php);
• Possible problems:
• Operating system level: zombies/orphans;
• Application level: resources handling;
• In case of demonizing - explicit exit in a child process.
12. OPERATING SYSTEM: ZOMBIES VS ORPHANS
LET’S FORK
OS keeps track of all processes.
• If a child process exists and this event is not handled by parent,
we get a zombie (defunct) (zombieDemo.php);
• If a parent process exits and child is still alive, it becomes an
orphan (parent PID = 1) (orphanDemo.php).
Not a real problem for a short living processes - important condition:
there should be time when both a parent and a child processes exit. If
parent process continues to run for a long time (daemon scenario),
than extra measures should be taken to prevent zombies duplication.
13. APPLICATION: RESOURCES HANDLING
LET’S FORK
File descriptors/handlers:
• Both processes use copies of the same descriptor, therefore
exists a risk of concurrent writes/reads to/from the descriptor.
• When process exits all descriptors are destructed by PHP,
therefore the process that is still alive will not be able to use it*.
* If you used to put code that closes descriptors correctly into shutdown
function be aware that in case of forked process if the process is
terminated because of the signal, shutdown function will not be called
unless you register also signal handler for corresponding signal.
14. SIGNALS
LET’S FORK
• Signals are software interrupts that deliver very short messages
(actually, an int) to process/processes.
• Some signals are catchable, some are not (SIGKILL).
• Install signal handlers for each signal: pcntl_signal(SIGTERM,
“handler”);
15. PARENT/CHILD COMMUNICATION
ADVANCED FORKING
• Explicit wait: pcntl_waitpid($pid, $status, $options);
• Catch SIGCHLD signal, then do pcntl_waitpid($pid, $status, $options);
• Use pcntl_wifexited()/pcntl_wifsignaled()/pcntl_wifstopped() to figure out how
(why) the child exited, then use:
• pcntl_wexitstatus() in case of normal exit to check the status OR
• pcntl_wtermsig()/pcntl_wstopsig() to check what actual signal the child has
received in case of exit because of signal;
Part of SIGCHLD handler that detects all the circumstances of the child process exit
16. DEALING WITH DAEMONS
ADVANCED FORKING
• Parent process should be responsible only for spawning children,
all tasks should be done by children;
• Parent process should keep tracking of children PIDs and should
be able to send at least two types of signals:
• Terminate gracefully;
• terminate immediately.
• Parent process should check total memory consumption (free
memory) and load average to decide if it is safe to fork;
• Children should rotate (exit) often to avoid memory leaks.
17. USEFUL RESOURCES
• http://www.hackingwithphp.com/16/1/0/process-control
• https://secure.php.net/manual/en/book.pcntl.php
• https://secure.php.net/manual/en/book.posix.php
• https://secure.php.net/manual/en/function.memory-get-
usage.php#120665
Magic formula to get total server memory in use:
$percentUsed = ($memory['used'] - $memory['kern']) * 100 / ($memory['used'] + $memory[‘free']);