-
Notifications
You must be signed in to change notification settings - Fork 427
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #317 from php-enqueue/amqp-signal-socket-issue-fix
[amqp] Fix socket and signal issue.
- Loading branch information
Showing
7 changed files
with
297 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
<?php | ||
|
||
namespace Enqueue\AmqpTools; | ||
|
||
class SignalSocketHelper | ||
{ | ||
/** | ||
* @var callable[] | ||
*/ | ||
private $handlers; | ||
|
||
/** | ||
* @var bool | ||
*/ | ||
private $wasThereSignal; | ||
|
||
/** | ||
* @var int[] | ||
*/ | ||
private $signals = [SIGTERM, SIGQUIT, SIGINT]; | ||
|
||
public function __construct() | ||
{ | ||
$this->handlers = []; | ||
} | ||
|
||
public function beforeSocket() | ||
{ | ||
// PHP 7.1 and higher | ||
if (false == function_exists('pcntl_signal_get_handler')) { | ||
return; | ||
} | ||
|
||
if ($this->handlers) { | ||
throw new \LogicException('The handlers property should be empty but it is not. The afterSocket method might not have been called.'); | ||
} | ||
if (null !== $this->wasThereSignal) { | ||
throw new \LogicException('The wasThereSignal property should be null but it is not. The afterSocket method might not have been called.'); | ||
} | ||
|
||
$this->wasThereSignal = false; | ||
|
||
foreach ($this->signals as $signal) { | ||
/** @var callable $handler */ | ||
$handler = pcntl_signal_get_handler($signal); | ||
|
||
pcntl_signal($signal, function ($signal) use ($handler) { | ||
var_dump('fuckk!'); | ||
$this->wasThereSignal = true; | ||
|
||
$handler && $handler($signal); | ||
}); | ||
|
||
$handler && $this->handlers[$signal] = $handler; | ||
} | ||
} | ||
|
||
public function afterSocket() | ||
{ | ||
// PHP 7.1 and higher | ||
if (false == function_exists('pcntl_signal_get_handler')) { | ||
return; | ||
} | ||
|
||
$this->wasThereSignal = null; | ||
|
||
foreach ($this->signals as $signal) { | ||
$handler = isset($this->handlers[$signal]) ? $this->handlers[$signal] : SIG_DFL; | ||
|
||
pcntl_signal($signal, $handler); | ||
} | ||
|
||
$this->handlers = []; | ||
} | ||
|
||
/** | ||
* @return bool | ||
*/ | ||
public function wasThereSignal() | ||
{ | ||
return (bool) $this->wasThereSignal; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
<?php | ||
|
||
namespace Enqueue\AmqpTools\Tests; | ||
|
||
use Enqueue\AmqpTools\SignalSocketHelper; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
class SignalSocketHelperTest extends TestCase | ||
{ | ||
/** | ||
* @var SignalSocketHelper | ||
*/ | ||
private $signalHelper; | ||
|
||
private $backupSigTermHandler; | ||
|
||
private $backupSigIntHandler; | ||
|
||
public function setUp() | ||
{ | ||
parent::setUp(); | ||
|
||
if (false == function_exists('pcntl_signal_get_handler')) { | ||
$this->markTestSkipped('PHP 7.1 and higher'); | ||
} | ||
|
||
$this->backupSigTermHandler = pcntl_signal_get_handler(SIGTERM); | ||
$this->backupSigIntHandler = pcntl_signal_get_handler(SIGINT); | ||
|
||
pcntl_signal(SIGTERM, SIG_DFL); | ||
pcntl_signal(SIGINT, SIG_DFL); | ||
|
||
$this->signalHelper = new SignalSocketHelper(); | ||
} | ||
|
||
public function tearDown() | ||
{ | ||
parent::tearDown(); | ||
|
||
if ($this->signalHelper) { | ||
$this->signalHelper->afterSocket(); | ||
} | ||
|
||
if ($this->backupSigTermHandler) { | ||
pcntl_signal(SIGTERM, $this->backupSigTermHandler); | ||
} | ||
|
||
if ($this->backupSigIntHandler) { | ||
pcntl_signal(SIGINT, $this->backupSigIntHandler); | ||
} | ||
} | ||
|
||
public function testShouldReturnFalseByDefault() | ||
{ | ||
$this->assertFalse($this->signalHelper->wasThereSignal()); | ||
} | ||
|
||
public function testShouldRegisterHandlerOnBeforeSocket() | ||
{ | ||
$this->signalHelper->beforeSocket(); | ||
|
||
$this->assertAttributeSame(false, 'wasThereSignal', $this->signalHelper); | ||
$this->assertAttributeSame([], 'handlers', $this->signalHelper); | ||
} | ||
|
||
public function testShouldRegisterHandlerOnBeforeSocketAndBackupCurrentOne() | ||
{ | ||
$handler = function () {}; | ||
|
||
pcntl_signal(SIGTERM, $handler); | ||
|
||
$this->signalHelper->beforeSocket(); | ||
|
||
$this->assertAttributeSame(false, 'wasThereSignal', $this->signalHelper); | ||
|
||
$handlers = $this->readAttribute($this->signalHelper, 'handlers'); | ||
|
||
$this->assertInternalType('array', $handlers); | ||
$this->assertArrayHasKey(SIGTERM, $handlers); | ||
$this->assertSame($handler, $handlers[SIGTERM]); | ||
} | ||
|
||
public function testRestoreDefaultPropertiesOnAfterSocket() | ||
{ | ||
$this->signalHelper->beforeSocket(); | ||
$this->signalHelper->afterSocket(); | ||
|
||
$this->assertAttributeSame(null, 'wasThereSignal', $this->signalHelper); | ||
$this->assertAttributeSame([], 'handlers', $this->signalHelper); | ||
} | ||
|
||
public function testRestorePreviousHandlerOnAfterSocket() | ||
{ | ||
$handler = function () {}; | ||
|
||
pcntl_signal(SIGTERM, $handler); | ||
|
||
$this->signalHelper->beforeSocket(); | ||
$this->signalHelper->afterSocket(); | ||
|
||
$this->assertSame($handler, pcntl_signal_get_handler(SIGTERM)); | ||
} | ||
|
||
public function testThrowsIfBeforeSocketCalledSecondTime() | ||
{ | ||
$this->signalHelper->beforeSocket(); | ||
|
||
$this->expectException(\LogicException::class); | ||
$this->expectExceptionMessage('The wasThereSignal property should be null but it is not. The afterSocket method might not have been called.'); | ||
$this->signalHelper->beforeSocket(); | ||
} | ||
|
||
public function testShouldReturnTrueOnWasThereSignal() | ||
{ | ||
$this->signalHelper->beforeSocket(); | ||
|
||
posix_kill(getmypid(), SIGINT); | ||
pcntl_signal_dispatch(); | ||
|
||
$this->assertTrue($this->signalHelper->wasThereSignal()); | ||
|
||
$this->signalHelper->afterSocket(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.