Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding documentation regarding DBAL usage. Updating existing examples. #31

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
76 changes: 73 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ Spork: PHP on a Fork
<?php

$manager = new Spork\ProcessManager();
$manager->fork(function() {
$manager->fork(function () {
// do something in another process!
return 'Hello from '.getmypid();
})->then(function(Spork\Fork $fork) {
return 'Hello from ' . getmypid();
})->then(function (Spork\Fork $fork) {
// do something in the parent process when it's done!
echo "{$fork->getPid()} says '{$fork->getResult()}'\n";
});
Expand All @@ -27,7 +27,77 @@ multiple batches and spread them across many processes.
$files = new RecursiveDirectoryIterator('/path/to/images');
$files = new RecursiveIteratorIterator($files);

$manager = new Spork\ProcessManager();
$manager->process($files, function(SplFileInfo $file) {
// upload this file
});

$manager->wait();
```

### Example: Working with Doctrine DBAL

When working with database connections, there is a known issue regarding parent/child processes.
From http://php.net/manual/en/function.pcntl-fork.php#70721:

> the child process inherits the parent's database connection.
> When the child exits, the connection is closed.
> If the parent is performing a query at this very moment, it is doing it on an already closed connection

This will mean that in our example, we will see a `SQLSTATE[HY000]: General error: 2006 MySQL server has gone away`
exception being thrown in the parent process.

One work-around for this situation is to force-close the DB connection before forking, by using the PRE_FORK event.

```php
<?php

$params = array(
'dbname' => '...',
'user' => '...',
'password' => '...',
'host' => '...',
'driver' => 'pdo_mysql',
);

$forks = 4;
$dataArray = range(0, 15);

$callback = function ($value) use ($params) {
// Child process acquires its own DB connection
$conn = Doctrine\DBAL\DriverManager::getConnection($params);
$conn->connect();

$sql = 'SELECT NOW() AS now';
$stmt = $conn->prepare($sql);
$stmt->execute();
$dbResult = $stmt->fetch();
$conn->close();

return ['pid' => getmypid(), 'value' => $value, 'result' => $dbResult];
};

// Get DB connection in parent
$parentConnection = Doctrine\DBAL\DriverManager::getConnection($params);
$parentConnection->connect();

$dispatcher = new Spork\EventDispatcher\EventDispatcher();
$dispatcher->addListener(Spork\EventDispatcher\Events::PRE_FORK, function () use ($parentConnection) {
$parentConnection->close();
});

$manager = new Spork\ProcessManager($dispatcher, null, true);

/** @var Spork\Fork $fork */
$fork = $manager->process($dataArray, $callback, new Spork\Batch\Strategy\ChunkStrategy($forks));
$manager->wait();

$result = $fork->getResult();

// Safe to use now
$sql = 'SELECT NOW() AS now_parent';
$stmt = $parentConnection->prepare($sql);
$stmt->execute();
$dbResult = $stmt->fetch();
$parentConnection->close();
```